Novidades no C# 6What's New in C# 6

A versão 6.0 do C# tinha muitos recursos para melhorar a produtividade para desenvolvedores.The 6.0 release of C# contained many features that improve productivity for developers. O efeito geral desses recursos é que você escreve código mais conciso e também mais legível.The overall effect of these features is that you write more concise code that is also more readable. A sintaxe contém menos cerimônia para várias práticas comuns.The syntax contains less ceremony for many common practices. É mais fácil de ver a intenção do design com menos cerimônia.It's easier to see the design intent with less ceremony. Aprenda bem esses recursos para ser mais produtivo e escrever um código mais legível.Learn these features well, and you'll be more productive and write more readable code. Você pode se concentrar mais nos recursos do que nos constructos da linguagem.You can concentrate more on your features than on the constructs of the language.

O restante deste artigo oferece uma visão geral de cada um desses recursos, com um link para explorá-los.The rest of this article provides an overview of each of these features, with a link to explore each feature. Explore também os recursos em uma exploração interativa sobre o C# 6 na seção de tutoriais.You can also explore the features in an interactive exploration on C# 6 in the tutorials section.

Propriedades automáticas somente leituraRead-only auto-properties

As Propriedades automáticas somente leitura fornecem uma sintaxe mais concisa para criar tipos imutáveis.Read-only auto-properties provide a more concise syntax to create immutable types. Você declara a propriedade automática apenas com um acessador get:You declare the auto-property with only a get accessor:

public string FirstName { get; }
public string LastName { get;  }

As propriedades FirstName e LastName podem ser definidas apenas no corpo do construtor da mesma classe:The FirstName and LastName properties can be set only in the body of the constructor of the same class:

public Student(string firstName, string lastName)
{
    if (IsNullOrWhiteSpace(lastName))
        throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));
    FirstName = firstName;
    LastName = lastName;
}

A tentativa de definir LastName em outro método gera um erro de compilação CS0200:Trying to set LastName in another method generates a CS0200 compilation error:

public class Student
{
    public string LastName { get;  }

    public void ChangeName(string newLastName)
    {
        // Generates CS0200: Property or indexer cannot be assigned to -- it is read only
        LastName = newLastName;
    }
}

Esse recurso habilita o suporte real à linguagem para criar tipos imutáveis e usar a sintaxe de propriedade automática mais concisa e conveniente.This feature enables true language support for creating immutable types and uses the more concise and convenient auto-property syntax.

Se a adição dessa sintaxe não remover um método acessível, essa será uma alteração compatível com binário.If adding this syntax doesn't remove an accessible method, it's a binary compatible change.

Inicializadores de propriedade automáticaAuto-property initializers

Os Inicializadores de propriedade automática permitem que você declare o valor inicial de uma propriedade automática como parte da declaração de propriedade.Auto-property initializers let you declare the initial value for an auto-property as part of the property declaration.

public ICollection<double> Grades { get; } = new List<double>();

O membro Grades é inicializado no local em que é declarado.The Grades member is initialized where it's declared. Isso facilita realizar a inicialização exatamente uma vez.That makes it easier to perform the initialization exactly once. A inicialização faz parte da declaração de propriedade, tornando mais fácil igualar a alocação de armazenamento com a interface pública para objetos Student.The initialization is part of the property declaration, making it easier to equate the storage allocation with the public interface for Student objects.

Membros de função aptos para expressãoExpression-bodied function members

Muitos membros que você escreve são instruções simples que poderiam ser expressões simples.Many members that you write are single statements that could be single expressions. Nesse caso, escreva um membro apto para expressão.Write an expression-bodied member instead. Isso funciona para métodos e propriedades somente leitura.It works for methods and read-only properties. Por exemplo, uma substituição de ToString() é, geralmente, uma ótima candidata:For example, an override of ToString() is often a great candidate:

public override string ToString() => $"{LastName}, {FirstName}";

Você também pode usar essa sintaxe para propriedades somente leitura:You can also use this syntax for read-only properties:

public string FullName => $"{FirstName} {LastName}";

A alteração de um membro existente para um membro de corpo da expressão é uma alteração compatível com binário.Changing an existing member to an expression bodied member is a binary compatible change.

usando estáticousing static

O aprimoramento using static permite que você importe os métodos estáticos de uma única classe.The using static enhancement enables you to import the static methods of a single class. Você especifica a classe que está usando:You specify the class you're using:

using static System.Math;

O Math não contém nenhum método de instância.The Math does not contain any instance methods. Você também pode usar using static para importar os métodos estáticos de uma classe para uma classe que tem os métodos estáticos e de instância.You can also use using static to import a class' static methods for a class that has both static and instance methods. Um dos exemplos mais úteis é String:One of the most useful examples is String:

using static System.String;

Observação

Você precisa usar o nome de classe totalmente qualificado, System.String em uma instrução using estática.You must use the fully qualified class name, System.String in a static using statement. Não é possível usar a palavra-chave string em vez disso.You cannot use the string keyword instead.

Quando importados de uma instrução static using, os métodos de extensão apenas estão no escopo quando chamados usando a sintaxe de invocação de método de extensão.When imported from a static using statement, extension methods are only in scope when called using the extension method invocation syntax. Eles não estão no escopo quando chamados como um método estático.They aren't in scope when called as a static method. Você verá isso com frequência em consultas LINQ.You'll often see this in LINQ queries. Você pode importar o padrão LINQ importando Enumerable ou Queryable.You can import the LINQ pattern by importing Enumerable, or Queryable.

using static System.Linq.Enumerable;

Normalmente, os métodos de extensão são chamados usando expressões de invocação de método de extensão.You typically call extension methods using extension method invocation expressions. No caso raro em que você os chama usando a sintaxe de chamada de método estático, adicione o nome de classe para resolver a ambiguidade.Adding the class name in the rare case where you call them using static method call syntax resolves ambiguity.

A diretiva static using também importa todos tipos aninhados.The static using directive also imports any nested types. Você pode referenciar qualquer tipo aninhado sem qualificação.You can reference any nested types without qualification.

Operadores condicionais nullNull-conditional operators

O operador condicional nulo torna as verificações de nulos muito mais fáceis e fluidas.The null conditional operator makes null checks much easier and fluid. Substitua o acesso do membro . por ?.:Replace the member access . with ?.:

var first = person?.FirstName; 

No exemplo anterior, a variável first é atribuída como null se o objeto person é null.In the preceding example, the variable first is assigned null if the person object is null. Caso contrário, ele receberá o valor da propriedade FirstName.Otherwise, it is assigned the value of the FirstName property. Mais importante, o ?. significa que essa linha de código não gera uma NullReferenceException quando a variável person é null.Most importantly, the ?. means that this line of code doesn't generate a NullReferenceException if the person variable is null. Em vez disso, ele causa um curto-circuito e retorna null.Instead, it short-circuits and returns null. Você também pode usar um operador condicional nulo para acesso de matriz ou de indexador.You can also use a null conditional operator for array or indexer access. Substitua [] por ?[] na expressão do índice.Replace [] with ?[] in the index expression.

A seguinte expressão retorna um string, independentemente do valor de person.The following expression returns a string, regardless of the value of person. Geralmente esse constructo é usado com o operador de união nulo para atribuir valores padrão quando uma das propriedades é null.You often use this construct with the null coalescing operator to assign default values when one of the properties is null. Quando a expressão causa um curto-circuito, o valor de null retornado é tipado para corresponder à expressão completa.When the expression short-circuits, the null value returned is typed to match the full expression.

first = person?.FirstName ?? "Unspecified";

Você também pode usar o ?. para invocar métodos condicionalmente.You can also use ?. to conditionally invoke methods. O uso mais comum das funções de membro com o operador condicional nulo é invocar delegados (ou manipuladores de eventos) com segurança que podem ser null.The most common use of member functions with the null conditional operator is to safely invoke delegates (or event handlers) that may be null. Você chamará o método Invoke do delegado usando o operador ?. para acessar o membro.You'll call the delegate's Invoke method using the ?. operator to access the member. Veja um exemplo no artigo padrões de delegado.You can see an example in the delegate patterns article.

As regras do operador ?. garantem que o lado esquerdo do operador é avaliado apenas uma vez.The rules of the ?. operator ensure that the left-hand side of the operator is evaluated only once. Isso permite diversas expressões, incluindo o exemplo a seguir usando manipuladores de eventos:It enables many idioms, including the following example using event handlers:

// preferred in C# 6:
this.SomethingHappened?.Invoke(this, eventArgs);

Garantir que o lado esquerdo seja avaliado apenas uma vez também permite que você use qualquer expressão, inclusive chamadas de método, no lado esquerdo do ?.Ensuring that the left side is evaluated only once also enables you to use any expression, including method calls, on the left side of the ?.

Interpolação de cadeias de caracteresString interpolation

Com o C# 6, o novo recurso de interpolação de cadeia de caracteres permite que você insira as expressões em uma cadeia de caracteres.With C# 6, the new string interpolation feature enables you to embed expressions in a string. Basta preceder a cadeia de caracteres com $ e usar expressões entre { e } em vez de ordinais:Simply preface the string with $and use expressions between { and } instead of ordinals:

public string FullName => $"{FirstName} {LastName}";

Este exemplo usa propriedades para as expressões substituídas.This example uses properties for the substituted expressions. Você pode usar qualquer expressão.You can use any expression. Por exemplo, você pode calcular a média do aluno como parte da interpolação:For example, you could compute a student's grade point average as part of the interpolation:

public string GetGradePointPercentage() =>
    $"Name: {LastName}, {FirstName}. G.P.A: {Grades.Average():F2}";

A linha de código anterior formata o valor de Grades.Average() como um número de ponto flutuante com duas casas decimais.The preceding line of code formats the value for Grades.Average() as a floating-point number with two decimal places.

Muitas vezes, pode ser necessário formatar a cadeia de caracteres produzida usando uma cultura específica.Often, you may need to format the string produced using a specific culture. Aproveite o fato de que o objeto produzido por uma interpolação de cadeia de caracteres pode ser convertido implicitamente em System.FormattableString.You use the fact that the object produced by a string interpolation can be implicitly converted to System.FormattableString. A instância de FormattableString contém a cadeia de caracteres de formato composto e os resultados da avaliação das expressões antes da conversão delas em cadeias de caracteres.The FormattableString instance contains the composite format string and the results of evaluating the expressions before converting them to strings. Use o método FormattableString.ToString(IFormatProvider) para especificar a cultura ao formatar uma cadeia de caracteres.Use the FormattableString.ToString(IFormatProvider) method to specify the culture when formatting a string. O exemplo a seguir produz uma cadeia de caracteres usando a cultura de-DE (alemão).The following example produces a string using the German (de-DE) culture. (Por padrão, a cultura alemã usa o caractere ',' para o separador decimal e o caractere '.' como o separador de milhares.)(By default, the German culture uses the ',' character for the decimal separator, and the '.' character as the thousands separator.)

FormattableString str = $"Average grade is {s.Grades.Average()}";
var gradeStr = str.ToString(new System.Globalization.CultureInfo("de-DE"));

Para familiarizar-se com a interpolação de cadeia de caracteres, confira o tutorial interativo Interpolação de cadeia de caracteres em C#, o artigo Interpolação de cadeia de caracteres e o tutorial Interpolação de cadeia de caracteres em C#.To get started with string interpolation, see the String interpolation in C# interactive tutorial, the String interpolation article, and the String interpolation in C# tutorial.

Filtros de exceçãoException filters

Os Filtros de Exceção são cláusulas que determinam quando uma determinada cláusula catch deve ser aplicada.Exception Filters are clauses that determine when a given catch clause should be applied. Se a expressão usada para um filtro de exceção é avaliada como true, a cláusula catch realiza seu processamento normal em uma exceção.If the expression used for an exception filter evaluates to true, the catch clause performs its normal processing on an exception. Se a expressão for avaliada como false, a cláusula catch será ignorada.If the expression evaluates to false, then the catch clause is skipped. Um uso é examinar informações sobre uma exceção para determinar se uma cláusula catch pode processar a exceção:One use is to examine information about an exception to determine if a catch clause can process the exception:

public static async Task<string> MakeRequest()
{
    WebRequestHandler webRequestHandler = new WebRequestHandler();
    webRequestHandler.AllowAutoRedirect = false;
    using (HttpClient client = new HttpClient(webRequestHandler))
    {
        var stringTask = client.GetStringAsync("https://docs.microsoft.com/en-us/dotnet/about/");
        try
        {
            var responseText = await stringTask;
            return responseText;
        }
        catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
        {
            return "Site Moved";
        }
    }
}

A expressão nameofThe nameof expression

A expressão nameof é avaliada como o nome de um símbolo.The nameof expression evaluates to the name of a symbol. É uma ótima maneira de fazer com que as ferramentas funcionem sempre que você precisar do nome de uma variável, de uma propriedade ou de um campo de membro.It's a great way to get tools working whenever you need the name of a variable, a property, or a member field. Um dos usos mais comuns para nameof é fornecer o nome de um símbolo que causou uma exceção:One of the most common uses for nameof is to provide the name of a symbol that caused an exception:

if (IsNullOrWhiteSpace(lastName))
    throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));

Outro uso é com aplicativos baseados em XAML que implementam a interface INotifyPropertyChanged:Another use is with XAML-based applications that implement the INotifyPropertyChanged interface:

public string LastName
{
    get { return lastName; }
    set
    {
        if (value != lastName)
        {
            lastName = value;
            PropertyChanged?.Invoke(this, 
                new PropertyChangedEventArgs(nameof(LastName)));
        }
    }
}
private string lastName;

Await em blocos catch e finallyAwait in Catch and Finally blocks

O C# 5 tinha várias limitações quanto ao local em que você poderia colocar expressões await.C# 5 had several limitations around where you could place await expressions. Com o C# 6, agora você pode usar await em expressões catch ou finally.With C# 6, you can now use await in catch or finally expressions. Isso geralmente é usado com cenários de registro em log:This is most often used with logging scenarios:

public static async Task<string> MakeRequestAndLogFailures()
{ 
    await logMethodEntrance();
    var client = new System.Net.Http.HttpClient();
    var streamTask = client.GetStringAsync("https://localHost:10000");
    try {
        var responseText = await streamTask;
        return responseText;
    } catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
    {
        await logError("Recovered from redirect", e);
        return "Site Moved";
    }
    finally
    {
        await logMethodExit();
        client.Dispose();
    }
}

Os detalhes de implementação para adicionar o suporte ao await dentro das cláusulas catch e finally garante que o comportamento seja consistente com o comportamento do código síncrono.The implementation details for adding await support inside catch and finally clauses ensure that the behavior is consistent with the behavior for synchronous code. Quando o código que é executado em uma cláusula catch ou finally realiza o lançamento, a execução procura por uma cláusula catch adequada no próximo bloco.When code executed in a catch or finally clause throws, execution looks for a suitable catch clause in the next surrounding block. Se houver uma exceção atual, essa exceção será perdida.If there was a current exception, that exception is lost. O mesmo acontece com expressões aguardadas em cláusulas catch e finally: um catch adequado é pesquisado e a exceção atual, se houver, será perdida.The same happens with awaited expressions in catch and finally clauses: a suitable catch is searched for, and the current exception, if any, is lost.

Observação

Esse comportamento é a razão pela qual recomenda-se escrever cláusulas catch e finally com cuidado, a fim de evitar introduzir novas exceções.This behavior is the reason it's recommended to write catch and finally clauses carefully, to avoid introducing new exceptions.

Inicializar coleções associativas usando indexadoresInitialize associative collections using indexers

Os inicializadores de índice são um dos dois recursos que deixam os inicializadores de coleção mais consistentes com o uso do índice.Index Initializers is one of two features that make collection initializers more consistent with index usage. Nas versões anteriores do C#, era possível usar inicializadores de coleção com coleções de estilo de sequência, incluindo Dictionary<TKey,TValue>, colocando os pares chave-valor entre chaves:In earlier releases of C#, you could use collection initializers with sequence style collections, including Dictionary<TKey,TValue>, by adding braces around key and value pairs:

private Dictionary<int, string> messages = new Dictionary<int, string>
{
    { 404, "Page not Found"},
    { 302, "Page moved, but left a forwarding address."},
    { 500, "The web server can't come out to play today."}
};

Você pode usá-los com coleções Dictionary<TKey,TValue> e outros tipos nos quais o método Add acessível aceite mais de um argumento.You can use them with Dictionary<TKey,TValue> collections and other types where the accessible Add method accepts more than one argument. A nova sintaxe permite a atribuição usando um índice na coleção:The new syntax supports assignment using an index into the collection:

private Dictionary<int, string> webErrors = new Dictionary<int, string>
{
    [404] = "Page not Found",
    [302] = "Page moved, but left a forwarding address.",
    [500] = "The web server can't come out to play today."
};

Esse recurso significa que os contêineres associativos podem ser inicializados usando uma sintaxe semelhante à que está em vigor para contêineres de sequência de várias versões.This feature means that associative containers can be initialized using syntax similar to what's been in place for sequence containers for several versions.

Métodos Add de extensão em inicializadores de coleçãoExtension Add methods in collection initializers

Outro recurso que facilita a inicialização de coleção é a capacidade de usar um método de extensão para o método Add.Another feature that makes collection initialization easier is the ability to use an extension method for the Add method. Esse recurso foi adicionado para a paridade com o Visual Basic.This feature was added for parity with Visual Basic. O recurso é mais útil quando você tem uma classe de coleção personalizada que tem um método com um nome diferente para adicionar novos itens semanticamente.The feature is most useful when you have a custom collection class that has a method with a different name to semantically add new items.

Resolução de sobrecarga aprimoradaImproved overload resolution

Esse último recurso provavelmente não será notado.This last feature is one you probably won't notice. Havia constructos nos quais a versão anterior do compilador do C# pode ter encontrado algumas chamadas de método que envolviam expressões lambda ambíguas.There were constructs where the previous version of the C# compiler may have found some method calls involving lambda expressions ambiguous. Considere este método:Consider this method:

static Task DoThings() 
{
     return Task.FromResult(0); 
}

Em versões anteriores do C#, haveria uma falha ao chamar esse método usando a sintaxe de grupo de método:In earlier versions of C#, calling that method using the method group syntax would fail:

Task.Run(DoThings); 

O compilador anterior não conseguia distinguir corretamente entre Task.Run(Action) e Task.Run(Func<Task>()).The earlier compiler couldn't distinguish correctly between Task.Run(Action) and Task.Run(Func<Task>()). Nas versões anteriores, você precisava usar uma expressão lambda como um argumento:In previous versions, you'd need to use a lambda expression as an argument:

Task.Run(() => DoThings());

O compilador do C# 6 determina corretamente que Task.Run(Func<Task>()) é uma opção melhor.The C# 6 compiler correctly determines that Task.Run(Func<Task>()) is a better choice.

Saída do compilador determinísticoDeterministic compiler output

A opção -deterministic instrui o compilador a produzir um assembly de saída idêntico byte a byte para compilações sucessivas dos mesmos arquivos de origem.The -deterministic option instructs the compiler to produce a byte-for-byte identical output assembly for successive compilations of the same source files.

Por padrão, cada compilação produz uma saída exclusiva em cada compilação.By default, every compilation produces unique output on each compilation. O compilador adiciona um carimbo de data/hora e um GUID gerado com base em números aleatórios.The compiler adds a timestamp, and a GUID generated from random numbers. Use essa opção se desejar comparar a saída byte a byte para garantir a consistência nos builds.You use this option if you want to compare the byte-for-byte output to ensure consistency across builds.

Para obter mais informações, confira o artigo Opção do compilador -deterministic.For more information, see the -deterministic compiler option article.