Formação
Módulo
Crie código legível com convenções, espaço em branco e comentários em C# - Training
Escreva código que seja mais fácil de ler, atualizar e dar suporte com convenções de nomenclatura, comentários e espaço em branco.
Este browser já não é suportado.
Atualize para o Microsoft Edge para tirar partido das mais recentes funcionalidades, atualizações de segurança e de suporte técnico.
As convenções de codificação são essenciais para manter a legibilidade, consistência e colaboração do código dentro de uma equipe de desenvolvimento. O código que segue as práticas do setor e as diretrizes estabelecidas é mais fácil de entender, manter e ampliar. A maioria dos projetos impõe um estilo consistente por meio de convenções de código. Os dotnet/docs
projetos e dotnet/samples
não são exceção. Nesta série de artigos, você aprende nossas convenções de codificação e as ferramentas que usamos para aplicá-las. Você pode tomar nossas convenções como estão, ou modificá-las para atender às necessidades da sua equipe.
Escolhemos as nossas convenções com base nos seguintes objetivos:
Importante
Essas diretrizes são usadas pela Microsoft para desenvolver exemplos e documentação. Eles foram adotados a partir das diretrizes .NET Runtime, C# Coding Style e compilador C# (roslyn). Escolhemos essas diretrizes porque foram testadas ao longo de vários anos de desenvolvimento Open Source. Eles ajudaram os membros da comunidade a participar dos projetos de tempo de execução e compiladores. Eles devem ser um exemplo de convenções comuns em C#, e não uma lista autorizada (consulte Framework Design Guidelines para isso).
Os objetivos de ensino e adoção são o motivo pelo qual a convenção de codificação docs difere das convenções de tempo de execução e compilador. Tanto o tempo de execução quanto o compilador têm métricas de desempenho rígidas para caminhos quentes. Muitas outras aplicações não. Nosso objetivo de ensino determina que não proíbamos nenhuma construção. Em vez disso, os exemplos mostram quando as construções devem ser usadas. Atualizamos as amostras de forma mais agressiva do que a maioria dos aplicativos de produção. Nossa meta de adoção exige que mostremos o código que você deve escrever hoje, mesmo quando o código escrito no ano passado não precisa de alterações.
Este artigo explica nossas diretrizes. As diretrizes evoluíram ao longo do tempo, e você encontrará exemplos que não seguem nossas diretrizes. Congratulamo-nos com PRs que coloquem essas amostras em conformidade ou questões que chamem a nossa atenção para amostras que devemos atualizar. As nossas diretrizes são Open Source e damos as boas-vindas a RPs e questões. No entanto, se o seu envio alterar essas recomendações, abra um problema para discussão primeiro. Você pode usar nossas diretrizes ou adaptá-las às suas necessidades.
As ferramentas podem ajudar a sua equipa a aplicar as suas convenções. Você pode habilitar a análise de código para impor as regras de sua preferência. Você também pode criar um editorconfig para que o Visual Studio imponha automaticamente suas diretrizes de estilo. Como ponto de partida, você pode copiar o arquivo do repositório dotnet/docs para usar nosso estilo.
Essas ferramentas tornam mais fácil para sua equipe adotar suas diretrizes preferidas. O Visual Studio aplica as regras em todos os .editorconfig
arquivos no escopo para formatar seu código. Você pode usar várias configurações para impor convenções corporativas, convenções de equipe e até convenções de projeto granulares.
A análise de código produz avisos e diagnósticos quando as regras habilitadas são violadas. Você configura as regras que deseja aplicar ao seu projeto. Em seguida, cada compilação de CI notifica os desenvolvedores quando eles violam qualquer uma das regras.
As seções a seguir descrevem as práticas que a equipe de documentos do .NET segue para preparar exemplos de código e exemplos. Em geral, siga estas práticas:
string
em vez de System.String, ou int
em vez de System.Int32.int
em vez de tipos não assinados. O uso de int
é comum em todo o C#, e é mais fácil interagir com outras bibliotecas quando você usa int
o . As exceções são para documentação específica para tipos de dados não assinados.var
somente quando um leitor puder inferir o tipo a partir da expressão. Os leitores visualizam as nossas amostras na plataforma de documentos. Eles não têm foco ou dicas de ferramentas que exibem o tipo de variáveis.Seguem-se orientações mais específicas.
Use a interpolação de cadeia de caracteres para concatenar cadeias curtas, conforme mostrado no código a seguir.
string displayName = $"{nameList[n].LastName}, {nameList[n].FirstName}";
Para acrescentar cadeias de caracteres em loops, especialmente quando você estiver trabalhando com grandes quantidades de texto, use um System.Text.StringBuilder objeto.
var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala";
var manyPhrases = new StringBuilder();
for (var i = 0; i < 10000; i++)
{
manyPhrases.Append(phrase);
}
//Console.WriteLine("tra" + manyPhrases);
var
em vez de string[]
.string[] vowels1 = { "a", "e", "i", "o", "u" };
var
o .var vowels2 = new string[] { "a", "e", "i", "o", "u" };
Func<>
e Action<>
em vez de definir tipos de delegados. Em uma classe, defina o método delegado.Action<string> actionExample1 = x => Console.WriteLine($"x is: {x}");
Action<string, string> actionExample2 = (x, y) =>
Console.WriteLine($"x is: {x}, y is {y}");
Func<string, int> funcExample1 = x => Convert.ToInt32(x);
Func<int, int, int> funcExample2 = (x, y) => x + y;
Func<>
ou Action<>
delegado.actionExample1("string for x");
actionExample2("string for x", "string for y");
Console.WriteLine($"The value is {funcExample1("1")}");
Console.WriteLine($"The sum is {funcExample2(1, 2)}");
Se você criar instâncias de um tipo delegado, use a sintaxe concisa. Em uma classe, defina o tipo de delegado e um método que tenha uma assinatura correspondente.
public delegate void Del(string message);
public static void DelMethod(string str)
{
Console.WriteLine("DelMethod argument: {0}", str);
}
Crie uma instância do tipo de delegado e chame-a. A declaração a seguir mostra a sintaxe condensada.
Del exampleDel2 = DelMethod;
exampleDel2("Hey");
A declaração a seguir usa a sintaxe completa.
Del exampleDel1 = new Del(DelMethod);
exampleDel1("Hey");
Use uma instrução try-catch para a maioria do tratamento de exceções.
static double ComputeDistance(double x1, double y1, double x2, double y2)
{
try
{
return Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
catch (System.ArithmeticException ex)
{
Console.WriteLine($"Arithmetic overflow or underflow: {ex}");
throw;
}
}
Simplifique seu código usando a instrução using C#. Se você tiver uma instrução try-finally na qual o finally
único código no bloco é uma chamada para o Dispose método, use uma using
instrução em vez disso.
No exemplo a seguir, a try-finally
instrução só chama Dispose
no finally
bloco .
Font bodyStyle = new Font("Arial", 10.0f);
try
{
byte charset = bodyStyle.GdiCharSet;
}
finally
{
if (bodyStyle != null)
{
((IDisposable)bodyStyle).Dispose();
}
}
Você pode fazer a mesma coisa com uma using
declaração.
using (Font arial = new Font("Arial", 10.0f))
{
byte charset2 = arial.GdiCharSet;
}
Use a nova using
sintaxe que não requer chaves:
using Font normalStyle = new Font("Arial", 10.0f);
byte charset3 = normalStyle.GdiCharSet;
Use &&
em vez de &
e ||
em vez de |
quando você executa comparações, como mostrado no exemplo a seguir.
Console.Write("Enter a dividend: ");
int dividend = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter a divisor: ");
int divisor = Convert.ToInt32(Console.ReadLine());
if ((divisor != 0) && (dividend / divisor) is var result)
{
Console.WriteLine("Quotient: {0}", result);
}
else
{
Console.WriteLine("Attempted division by 0 ends up here.");
}
Se o divisor for 0, a segunda cláusula na if
instrução causaria um erro em tempo de execução. Mas o operador && entra em curto-circuito quando a primeira expressão é falsa. Ou seja, não avalia a segunda expressão. O operador & avaliaria ambos, resultando em um erro em tempo de execução quando divisor
é 0.
Use uma das formas concisas de instanciação de objeto, conforme mostrado nas declarações a seguir.
var firstExample = new ExampleClass();
ExampleClass instance2 = new();
As declarações anteriores equivalem à declaração seguinte.
ExampleClass secondExample = new ExampleClass();
Use inicializadores de objeto para simplificar a criação de objetos, conforme mostrado no exemplo a seguir.
var thirdExample = new ExampleClass { Name = "Desktop", ID = 37414,
Location = "Redmond", Age = 2.3 };
O exemplo a seguir define as mesmas propriedades do exemplo anterior, mas não usa inicializadores.
var fourthExample = new ExampleClass();
fourthExample.Name = "Desktop";
fourthExample.ID = 37414;
fourthExample.Location = "Redmond";
fourthExample.Age = 2.3;
public Form2()
{
this.Click += (s, e) =>
{
MessageBox.Show(
((MouseEventArgs)e).Location.ToString());
};
}
A expressão lambda encurta a seguinte definição tradicional.
public Form1()
{
this.Click += new EventHandler(Form1_Click);
}
void Form1_Click(object? sender, EventArgs e)
{
MessageBox.Show(((MouseEventArgs)e).Location.ToString());
}
Chame membros estáticos usando o nome da classe: ClassName.StaticMember. Essa prática torna o código mais legível, tornando o acesso estático claro. Não qualifique um membro estático definido em uma classe base com o nome de uma classe derivada. Enquanto esse código é compilado, a legibilidade do código é enganosa, e o código pode quebrar no futuro se você adicionar um membro estático com o mesmo nome à classe derivada.
Use nomes significativos para variáveis de consulta. O exemplo a seguir usa seattleCustomers
para clientes que estão localizados em Seattle.
var seattleCustomers = from customer in customers
where customer.City == "Seattle"
select customer.Name;
Use aliases para certificar-se de que os nomes de propriedade de tipos anônimos estão corretamente em maiúsculas, usando a caixa Pascal.
var localDistributors =
from customer in customers
join distributor in distributors on customer.City equals distributor.City
select new { Customer = customer, Distributor = distributor };
Renomeie propriedades quando os nomes de propriedade no resultado forem ambíguos. Por exemplo, se sua consulta retornar um nome de cliente e um ID de distribuidor, em vez de deixá-los como Name
e ID
no resultado, renomeie-os para esclarecer que Name
é o nome de um cliente e ID
é o ID de um distribuidor.
var localDistributors2 =
from customer in customers
join distributor in distributors on customer.City equals distributor.City
select new { CustomerName = customer.Name, DistributorID = distributor.ID };
Use a digitação implícita na declaração de variáveis de consulta e variáveis de intervalo. Esta orientação sobre digitação implícita em consultas LINQ substitui as regras gerais para variáveis locais digitadas implicitamente. As consultas LINQ geralmente usam projeções que criam tipos anônimos. Outras expressões de consulta criam resultados com tipos genéricos aninhados. As variáveis digitadas implícitas são geralmente mais legíveis.
var seattleCustomers = from customer in customers
where customer.City == "Seattle"
select customer.Name;
Alinhe as cláusulas de consulta sob a from
cláusula, conforme mostrado nos exemplos anteriores.
Use where
cláusulas antes de outras cláusulas de consulta para garantir que cláusulas de consulta posteriores operem no conjunto reduzido e filtrado de dados.
var seattleCustomers2 = from customer in customers
where customer.City == "Seattle"
orderby customer.Name
select customer;
Use várias from
cláusulas em vez de uma join
cláusula para acessar coleções internas. Por exemplo, uma coleção de Student
objetos pode conter uma coleção de pontuações de teste. Quando a consulta a seguir é executada, ela retorna cada pontuação acima de 90, juntamente com o sobrenome do aluno que recebeu a pontuação.
var scoreQuery = from student in students
from score in student.Scores!
where score > 90
select new { Last = student.LastName, score };
Use a digitação implícita para variáveis locais quando o tipo da variável for óbvio do lado direito da atribuição.
var message = "This is clearly a string.";
var currentTemperature = 27;
Não use var quando o tipo não estiver aparente do lado direito da atribuição. Não assuma que o tipo é claro a partir de um nome de método. Um tipo de variável é considerado claro se for um new
operador, uma conversão explícita ou atribuição a um valor literal.
int numberOfIterations = Convert.ToInt32(Console.ReadLine());
int currentMaximum = ExampleClass.ResultSoFar();
Não use nomes de variáveis para especificar o tipo da variável. Pode não estar correto. Em vez disso, use o tipo para especificar o tipo e use o nome da variável para indicar as informações semânticas da variável. O exemplo a seguir deve ser usado string
para o tipo e algo como iterations
indicar o significado das informações lidas do console.
var inputInt = Console.ReadLine();
Console.WriteLine(inputInt);
Evite o uso de var
no lugar de dinâmica. Use dynamic
quando quiser inferência de tipo em tempo de execução. Para obter mais informações, consulte Usando o tipo dinâmico (Guia de Programação em C#).
Use a digitação implícita para a variável de loop em for
loops.
O exemplo a seguir usa a digitação implícita em uma for
instrução.
var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala";
var manyPhrases = new StringBuilder();
for (var i = 0; i < 10000; i++)
{
manyPhrases.Append(phrase);
}
//Console.WriteLine("tra" + manyPhrases);
Não use digitação implícita para determinar o tipo da variável de loop em foreach
loops. Na maioria dos casos, o tipo de elementos na coleção não é imediatamente óbvio. O nome da coleção não deve ser usado apenas para inferir o tipo de seus elementos.
O exemplo a seguir usa a digitação explícita em uma foreach
instrução.
foreach (char ch in laugh)
{
if (ch == 'h')
{
Console.Write("H");
}
else
{
Console.Write(ch);
}
}
Console.WriteLine();
use o tipo implícito para as sequências de resultados em consultas LINQ. A seção sobre LINQ explica que muitas consultas LINQ resultam em tipos anônimos onde tipos implícitos devem ser usados. Outras consultas resultam em tipos genéricos aninhados onde var
é mais legível.
Nota
Tenha cuidado para não alterar acidentalmente um tipo de elemento da coleção iterável. Por exemplo, é fácil alternar de System.Linq.IQueryable para System.Collections.IEnumerable em uma foreach
instrução, o que altera a execução de uma consulta.
Algumas das nossas amostras explicam o tipo natural de uma expressão. Essas amostras devem ser usadas var
para que o compilador escolha o tipo natural. Embora esses exemplos sejam menos óbvios, o uso de var
é necessário para a amostra. O texto deve explicar o comportamento.
Quando uma using
diretiva está fora de uma declaração de namespace, esse namespace importado é seu nome totalmente qualificado. O nome totalmente qualificado é mais claro. Quando a using
diretiva está dentro do namespace, ela pode ser relativa a esse namespace ou seu nome totalmente qualificado.
using Azure;
namespace CoolStuff.AwesomeFeature
{
public class Awesome
{
public void Stuff()
{
WaitUntil wait = WaitUntil.Completed;
// ...
}
}
}
Supondo que haja uma referência (direta ou indireta) à WaitUntil classe.
Agora, vamos mudá-lo um pouco:
namespace CoolStuff.AwesomeFeature
{
using Azure;
public class Awesome
{
public void Stuff()
{
WaitUntil wait = WaitUntil.Completed;
// ...
}
}
}
E compila hoje. E amanhã. Mas então, em algum momento da próxima semana, o código anterior (intocado) falha com dois erros:
- error CS0246: The type or namespace name 'WaitUntil' could not be found (are you missing a using directive or an assembly reference?)
- error CS0103: The name 'WaitUntil' does not exist in the current context
Uma das dependências introduziu essa classe em um namespace e termina com .Azure
:
namespace CoolStuff.Azure
{
public class SecretsManagement
{
public string FetchFromKeyVault(string vaultId, string secretId) { return null; }
}
}
Uma using
diretiva colocada dentro de um namespace é sensível ao contexto e complica a resolução de nomes. Neste exemplo, é o primeiro namespace encontrado.
CoolStuff.AwesomeFeature.Azure
CoolStuff.Azure
Azure
Adicionar um novo namespace que corresponda CoolStuff.Azure
ou CoolStuff.AwesomeFeature.Azure
corresponda antes do namespace global Azure
. Você pode resolvê-lo adicionando o global::
modificador à using
declaração. No entanto, é mais fácil colocar using
declarações fora do namespace.
namespace CoolStuff.AwesomeFeature
{
using global::Azure;
public class Awesome
{
public void Stuff()
{
WaitUntil wait = WaitUntil.Completed;
// ...
}
}
}
Em geral, use o seguinte formato para exemplos de código:
Use comentários de linha única (//
) para breves explicações.
Evite comentários com várias linhas (/* */
) para explicações mais longas.
Os comentários nos exemplos de código não estão localizados. Isso significa que as explicações incorporadas no código não serão traduzidas. Texto explicativo mais longo deve ser colocado no artigo complementar, para que possa ser localizado.
Para descrever métodos, classes, campos e todos os membros públicos usam comentários XML.
Coloque o comentário em uma linha separada, não no final de uma linha de código.
Comece o texto do comentário com uma letra maiúscula.
Termine o texto do comentário com um ponto.
Insira um espaço entre o delimitador de comentários (//
) e o texto do comentário, conforme mostrado no exemplo a seguir.
// The following declaration creates a query. It does not run
// the query.
Um bom layout usa a formatação para enfatizar a estrutura do seu código e para tornar o código mais fácil de ler. Os exemplos e exemplos da Microsoft estão em conformidade com as seguintes convenções:
Use as configurações padrão do Editor de Códigos (recuo inteligente, recuos de quatro caracteres, guias salvas como espaços). Para obter mais informações, consulte Opções, Editor de texto, C#, Formatação.
Escreva apenas uma instrução por linha.
Escreva apenas uma declaração por linha.
Se as linhas de continuação não forem recuadas automaticamente, recue-as uma parada de tabulação (quatro espaços).
Adicione pelo menos uma linha em branco entre definições de método e definições de propriedade.
Use parênteses para tornar as cláusulas em uma expressão aparente, conforme mostrado no código a seguir.
if ((startX > endX) && (startX > previousX))
{
// Take appropriate action.
}
As exceções são quando o exemplo explica a precedência do operador ou da expressão.
Siga as diretrizes em Diretrizes de codificação segura.
Comentários do .NET
O .NET é um projeto código aberto. Selecione um link para fornecer comentários:
Formação
Módulo
Crie código legível com convenções, espaço em branco e comentários em C# - Training
Escreva código que seja mais fácil de ler, atualizar e dar suporte com convenções de nomenclatura, comentários e espaço em branco.