Design de parâmetros
Nota
Este conteúdo é reimpresso com permissão da Pearson Education, Inc., a partir de Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition. Essa edição foi publicada em 2008 e, desde então, o livro foi totalmente revisto na terceira edição. Algumas das informações nesta página podem estar desatualizadas.
Esta seção fornece diretrizes gerais sobre design de parâmetros, incluindo seções com diretrizes para verificar argumentos. Além disso, você deve consultar as diretrizes descritas em Parâmetros de nomenclatura.
✔️ DO use o tipo de parâmetro menos derivado que fornece a funcionalidade exigida pelo membro.
Por exemplo, suponha que você queira criar um método que enumere uma coleção e imprima cada item no console. Tal método deve tomar IEnumerable como parâmetro, não ArrayList ou IList, por exemplo.
❌ NÃO utilize parâmetros reservados.
Se for necessária mais entrada para um membro em alguma versão futura, uma nova sobrecarga pode ser adicionada.
❌ NÃO tenha métodos expostos publicamente que tomem ponteiros, matrizes de ponteiros ou matrizes multidimensionais como parâmetros.
Ponteiros e matrizes multidimensionais são relativamente difíceis de usar corretamente. Em quase todos os casos, as APIs podem ser redesenhadas para evitar tomar esses tipos como parâmetros.
✔️ DO coloque todos os out
parâmetros seguindo todos os subvalores e ref
parâmetros (excluindo matrizes de parâmetros), mesmo que isso resulte em uma inconsistência na ordenação de parâmetros entre sobrecargas (consulte Sobrecarga de membros).
Os out
parâmetros podem ser vistos como valores de retorno extras, e agrupá-los torna a assinatura do método mais fácil de entender.
✔️ NÃO seja consistente em nomear parâmetros ao substituir membros ou implementar membros da interface.
Isso comunica melhor a relação entre os métodos.
Escolhendo entre parâmetros enum e booleanos
✔️ USE enums se um membro tiver dois ou mais parâmetros booleanos.
❌ NÃO use booleanos a menos que tenha certeza absoluta de que nunca haverá necessidade de mais de dois valores.
Enums lhe dão algum espaço para adição futura de valores, mas você deve estar ciente de todas as implicações de adicionar valores aos enums, que são descritos em Enum Design.
✔️ CONSIDERE o uso de Booleans para parâmetros do construtor que são realmente valores de dois estados e são simplesmente usados para inicializar propriedades booleanas.
Validando argumentos
✔️ VALIDE argumentos passados a membros públicos, protegidos ou explicitamente implementados. Lance System.ArgumentException, ou uma de suas subclasses, se a validação falhar.
Note-se que a validação real não tem necessariamente de acontecer no próprio membro público ou protegido. Pode acontecer em um nível mais baixo em alguma rotina privada ou interna. O ponto principal é que toda a área de superfície exposta aos usuários finais verifica os argumentos.
✔️ DO throw ArgumentNullException se um argumento null for passado e o membro não suportar argumentos nulos.
✔️ NÃO valide parâmetros de enum.
Não assuma que os argumentos de enum estarão no intervalo definido pelo enum. O CLR permite converter qualquer valor inteiro em um valor de enum, mesmo que o valor não esteja definido no enum.
❌ NÃO utilize Enum.IsDefined para verificações da gama de enum.
✔️ ESTEJA ciente de que os argumentos mutáveis podem ter mudado depois de validados.
Se o membro for sensível à segurança, você é encorajado a fazer uma cópia e, em seguida, validar e processar o argumento.
Transmissão de Parâmetro
Da perspetiva de um designer de estrutura, existem três grupos principais de parâmetros: parâmetros por valor, ref
parâmetros e out
parâmetros.
Quando um argumento é passado através de um parâmetro by-value, o membro recebe uma cópia do argumento real passado. Se o argumento for um tipo de valor, uma cópia do argumento será colocada na pilha. Se o argumento for um tipo de referência, uma cópia da referência será colocada na pilha. As linguagens CLR mais populares, como C#, VB.NET e C++, usam como padrão a passagem de parâmetros por valor.
Quando um argumento é passado através de um ref
parâmetro, o membro recebe uma referência ao argumento real passado. Se o argumento for um tipo de valor, uma referência ao argumento será colocada na pilha. Se o argumento for um tipo de referência, uma referência à referência será colocada na pilha. Ref
Os parâmetros podem ser usados para permitir que o membro modifique os argumentos passados pelo chamador.
Out
Os parâmetros são semelhantes aos ref
parâmetros, com algumas pequenas diferenças. O parâmetro é inicialmente considerado não atribuído e não pode ser lido no corpo do membro antes de lhe ser atribuído algum valor. Além disso, o parâmetro tem que ser atribuído algum valor antes que o membro retorne.
❌ EVITE usar out
ou ref
parâmetros.
O uso out
de parâmetros or ref
requer experiência com ponteiros, compreensão de como os tipos de valor e tipos de referência diferem e manipulação de métodos com vários valores de retorno. Além disso, a diferença entre out
e ref
parâmetros não é amplamente compreendida. Os arquitetos de estrutura que projetam para um público geral não devem esperar que os usuários se tornem proficientes em trabalhar com out
parâmetros OR ref
.
❌ NÃO passe tipos de referência por referência.
Existem algumas exceções limitadas à regra, como um método que pode ser usado para trocar referências.
Membros com número variável de parâmetros
Os membros que podem aceitar um número variável de argumentos são expressos fornecendo um parâmetro de matriz. Por exemplo, String fornece o seguinte método:
public class String {
public static string Format(string format, object[] parameters);
}
Um usuário pode então chamar o String.Format método, da seguinte maneira:
String.Format("File {0} not found in {1}",new object[]{filename,directory});
Adicionar a palavra-chave C# params a um parâmetro de matriz altera o parâmetro para um chamado parâmetro de matriz de parâmetros e fornece um atalho para criar uma matriz temporária.
public class String {
public static string Format(string format, params object[] parameters);
}
Isso permite que o usuário chame o método passando os elementos da matriz diretamente na lista de argumentos.
String.Format("File {0} not found in {1}",filename,directory);
Observe que a palavra-chave params pode ser adicionada somente ao último parâmetro na lista de parâmetros.
✔️ CONSIDERE adicionar a palavra-chave params aos parâmetros de matriz se você espera que os usuários finais passem matrizes com um pequeno número de elementos. Se for esperado que muitos elementos sejam passados em cenários comuns, os usuários provavelmente não passarão esses elementos em linha de qualquer maneira, e, portanto, a palavra-chave params não é necessária.
❌ EVITE usar matrizes de parâmetros se o chamador quase sempre tiver a entrada já em uma matriz.
Por exemplo, membros com parâmetros de matriz de bytes quase nunca seriam chamados passando bytes individuais. Por esse motivo, parâmetros de matriz de bytes no .NET Framework não usam a palavra-chave params.
❌ NÃO use matrizes params se a matriz for modificada pelo membro que usa o parâmetro params array.
Devido ao fato de que muitos compiladores transformam os argumentos para o membro em uma matriz temporária no local de chamada, a matriz pode ser um objeto temporário e, portanto, quaisquer modificações na matriz serão perdidas.
✔️ CONSIDERE usar a palavra-chave params em uma sobrecarga simples, mesmo que uma sobrecarga mais complexa não possa usá-la.
Pergunte a si mesmo se os usuários valorizariam ter a matriz de parâmetros em uma sobrecarga, mesmo que não estivesse em todas as sobrecargas.
✔️ DO tente ordenar parâmetros para tornar possível o uso da palavra-chave params.
✔️ CONSIDERE fornecer sobrecargas especiais e caminhos de código para chamadas com um pequeno número de argumentos em APIs extremamente sensíveis ao desempenho.
Isso torna possível evitar a criação de objetos de matriz quando a API é chamada com um pequeno número de argumentos. Forme os nomes dos parâmetros tomando uma forma singular do parâmetro array e adicionando um sufixo numérico.
Você só deve fazer isso se for usar um caso especial para todo o caminho do código, não apenas criar uma matriz e chamar o método mais geral.
✔️ ESTEJA ciente de que null pode ser passado como um argumento de matriz params.
Você deve validar se a matriz não é nula antes de processar.
❌ NÃO utilize os varargs
métodos, também conhecidos como reticências.
Algumas linguagens CLR, como C++, suportam uma convenção alternativa para passar listas de parâmetros variáveis chamadas varargs
métodos. A convenção não deve ser usada em estruturas, porque não é compatível com CLS.
Parâmetros de ponteiro
Em geral, os ponteiros não devem aparecer na área de superfície pública de uma estrutura de código gerenciado bem projetada. Na maioria das vezes, os ponteiros devem ser encapsulados. No entanto, em alguns casos, são necessários ponteiros por razões de interoperabilidade, e o uso de ponteiros nesses casos é apropriado.
✔️ DO fornece uma alternativa para qualquer membro que usa um argumento de ponteiro, porque os ponteiros não são compatíveis com CLS.
❌ EVITE fazer verificações dispendiosas de argumentos de ponteiro.
✔️ SIGA convenções comuns relacionadas a ponteiros ao projetar membros com ponteiros.
Por exemplo, não há necessidade de passar o índice inicial, porque a aritmética de ponteiro simples pode ser usada para obter o mesmo resultado.
© Partes 2005, 2009 Microsoft Corporation. Todos os direitos reservados.
Reimpresso com permissão da Pearson Education, Inc., de Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition por Krzysztof Cwalina e Brad Abrams, publicado em 22 de outubro de 2008 por Addison-Wesley Professional como parte da Microsoft Windows Development Series.