Co nowego w C# 6What's New in C# 6

Wersja 6,0 systemu C# zawiera wiele funkcji, które zwiększają produktywność dla deweloperów.The 6.0 release of C# contained many features that improve productivity for developers. Ogólnym efektem tych funkcji jest pisanie bardziej zwięzłego kodu, który jest również bardziej czytelny.The overall effect of these features is that you write more concise code that is also more readable. Składnia zawiera mniej procedury dla wielu typowych praktyk.The syntax contains less ceremony for many common practices. Łatwiej jest zobaczyć cel projektowania z mniejszą procedury.It's easier to see the design intent with less ceremony. Poznaj te funkcje również, aby zwiększyć produktywność i napisać bardziej czytelny kod.Learn these features well, and you'll be more productive and write more readable code. Możesz skoncentrować się na swoich funkcjach, niż w konstrukcjach języka.You can concentrate more on your features than on the constructs of the language.

Pozostała część tego artykułu zawiera omówienie każdej z tych funkcji z linkiem do eksplorowania każdej funkcji.The rest of this article provides an overview of each of these features, with a link to explore each feature. Możesz również zapoznać się z funkcjami w interaktywnej eksplorowaniu C# w sekcji samouczki.You can also explore the features in an interactive exploration on C# 6 in the tutorials section.

Autowłaściwości tylko do odczytuRead-only auto-properties

Właściwości autotylko do odczytu zapewniają bardziej zwięzłą składnię do tworzenia niezmiennych typów.Read-only auto-properties provide a more concise syntax to create immutable types. Właściwość autoproperty deklaruje się tylko przy użyciu metody dostępu get:You declare the auto-property with only a get accessor:

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

Właściwości FirstName iLastName można ustawić tylko w treści konstruktora tej samej klasy: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;
}

Próba ustawienia LastName w innej metodzie spowoduje CS0200 wygenerowanie błędu kompilacji: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;
    }
}

Ta funkcja umożliwia obsługę języków w przypadku tworzenia niezmiennych typów i używa bardziej zwięzłej i wygodnej składni autowłaściwości.This feature enables true language support for creating immutable types and uses the more concise and convenient auto-property syntax.

Jeśli dodanie tej składni nie spowoduje usunięcia dostępnej metody, jest to zgodnaz binarną zmianą.If adding this syntax doesn't remove an accessible method, it's a binary compatible change.

Inicjatory właściwości automatycznejAuto-property initializers

Inicjatory właściwości automatycznie umożliwiają deklarowanie wartości początkowej właściwości autoproperty jako części deklaracji właściwości.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>();

Element Grades członkowski jest inicjowany w miejscu, w którym został zadeklarowany.The Grades member is initialized where it's declared. Dzięki temu można łatwiej wykonać inicjalizację dokładnie jeden raz.That makes it easier to perform the initialization exactly once. Inicjalizacja jest częścią deklaracji właściwości, dzięki czemu łatwiej jest zrównać alokację magazynu z interfejsem publicznym dla Student obiektów.The initialization is part of the property declaration, making it easier to equate the storage allocation with the public interface for Student objects.

Składowe funkcji w postaci wyrażeńExpression-bodied function members

Wiele składowych, które piszesz, to pojedyncze instrukcje, które mogą być pojedynczymi wyrażeniami.Many members that you write are single statements that could be single expressions. Zamiast tego Napisz element członkowski z wyrażeniem.Write an expression-bodied member instead. Działa w przypadku metod i właściwości tylko do odczytu.It works for methods and read-only properties. Na przykład przesłonięcie ToString() jest często doskonałym kandydatem:For example, an override of ToString() is often a great candidate:

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

Tej składni można także użyć do właściwości tylko do odczytu:You can also use this syntax for read-only properties:

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

Zmiana istniejącego elementu członkowskiego na wyrażenie składowane składowe jest zgodnąz binarną zmianą.Changing an existing member to an expression bodied member is a binary compatible change.

Używanie staticusing static

Użycie statycznego rozszerzenia umożliwia importowanie metod statycznych pojedynczej klasy.The using static enhancement enables you to import the static methods of a single class. Należy określić klasę, z której korzystasz:You specify the class you're using:

using static System.Math;

Math Nie zawiera żadnych metod wystąpienia.The Math does not contain any instance methods. Można również użyć using static do zaimportowania metod statycznych klasy dla klasy, która ma zarówno metody statyczne, jak i wystąpienia.You can also use using static to import a class' static methods for a class that has both static and instance methods. Jednym z najbardziej przydatnych przykładów jest String:One of the most useful examples is String:

using static System.String;

Uwaga

Należy użyć System.String w pełni kwalifikowanej nazwy klasy w statycznej instrukcji using.You must use the fully qualified class name, System.String in a static using statement. Nie można użyć string słowa kluczowego.You cannot use the string keyword instead.

W przypadku zaimportowania z static using instrukcji metody rozszerzające są tylko w zakresie, gdy są wywoływane przy użyciu składni wywołania metody rozszerzenia.When imported from a static using statement, extension methods are only in scope when called using the extension method invocation syntax. Nie są one w zakresie, gdy jest wywoływana jako metoda statyczna.They aren't in scope when called as a static method. Często są one widoczne w zapytaniach LINQ.You'll often see this in LINQ queries. Wzorzec LINQ można zaimportować przez Enumerablezaimportowanie lub. QueryableYou can import the LINQ pattern by importing Enumerable, or Queryable.

using static System.Linq.Enumerable;

Metody rozszerzające są zwykle wywoływane przy użyciu wyrażeń wywołania metody rozszerzenia.You typically call extension methods using extension method invocation expressions. Dodanie nazwy klasy w rzadkim przypadku, gdy są one wywoływane przy użyciu składni wywołania metody statycznej, rozwiązuje niejednoznaczności.Adding the class name in the rare case where you call them using static method call syntax resolves ambiguity.

static using Dyrektywa importuje również wszystkie typy zagnieżdżone.The static using directive also imports any nested types. Można odwoływać się do wszelkich zagnieżdżonych typów bez kwalifikacji.You can reference any nested types without qualification.

Operatory warunkowe o wartości nullNull-conditional operators

Operator warunkowy o wartości null sprawia, że sprawdzanie wartości null jest znacznie łatwiejsze i płynne.The null conditional operator makes null checks much easier and fluid. Zastąp element członkowski . dostępem ?.:Replace the member access . with ?.:

var first = person?.FirstName; 

W poprzednim przykładzie zmienna first jest przypisywana null , jeśli obiektem jest null.In the preceding example, the variable first is assigned null if the person object is null. W przeciwnym razie jest przypisana wartość FirstName właściwości.Otherwise, it is assigned the value of the FirstName property. Co ważniejsze, ?. oznacza, że ten wiersz kodu nie generuje elementu NullReferenceException , jeśli person zmienna jest null.Most importantly, the ?. means that this line of code doesn't generate a NullReferenceException if the person variable is null. Zamiast tego, krótkie obwody i zwraca null.Instead, it short-circuits and returns null. Można również użyć operatora warunkowego null dla dostępu do tablicy lub indeksatora.You can also use a null conditional operator for array or indexer access. Zamień []nawwyrażeniuindeksu ?[] .Replace [] with ?[] in the index expression.

Poniższe wyrażenie zwraca string, niezależnie od personwartości.The following expression returns a string, regardless of the value of person. Ta konstrukcja jest często używana z operatorem łączenia wartości null do przypisywania wartości domyślnych, gdy jedna nullz właściwości jest.You often use this construct with the null coalescing operator to assign default values when one of the properties is null. W przypadku krótkich obwodów null wyrażenia zwracana wartość jest wpisana w celu dopasowania pełnego wyrażenia.When the expression short-circuits, the null value returned is typed to match the full expression.

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

Można również użyć ?. do warunkowego wywoływania metod.You can also use ?. to conditionally invoke methods. Najbardziej typowym zastosowaniem funkcji Członkowskich z operatorem warunkowym null jest bezpieczne wywoływanie delegatów (lub obsługi zdarzeń), które nullmogą być.The most common use of member functions with the null conditional operator is to safely invoke delegates (or event handlers) that may be null. Wywołamy Invoke metodę delegata przy użyciu operatora, ?. Aby uzyskać dostęp do elementu członkowskiego.You'll call the delegate's Invoke method using the ?. operator to access the member. W artykule dotyczącego wzorców delegatów można zobaczyć przykład.You can see an example in the delegate patterns article.

Reguły ?. operatora zapewniają, że lewa strona operatora jest szacowana tylko raz.The rules of the ?. operator ensure that the left-hand side of the operator is evaluated only once. Umożliwia ona wiele idiomy, w tym Poniższy przykład, przy użyciu obsługi zdarzeń:It enables many idioms, including the following example using event handlers:

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

Upewnienie się, że lewa strona jest szacowana tylko raz, również umożliwia użycie dowolnego wyrażenia, w tym wywołań metod, po lewej stronie?.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 ?.

Interpolacja ciągówString interpolation

W C# przypadku opcji 6 Nowa funkcja interpolacji ciągu umożliwia osadzanie wyrażeń w ciągu.With C# 6, the new string interpolation feature enables you to embed expressions in a string. Wystarczy wpisać ciąg z $wyrażeniami i używać wyrażeń między { i } zamiast liczb porządkowych:Simply preface the string with $and use expressions between { and } instead of ordinals:

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

W tym przykładzie zastosowano właściwości przedstawionych wyrażeń.This example uses properties for the substituted expressions. Możesz użyć dowolnego wyrażenia.You can use any expression. Na przykład można obliczyć średnią punktu oceny studenta w ramach interpolacji: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}";

Poprzedni wiersz kodu formatuje wartość Grades.Average() jako liczbę zmiennoprzecinkową z dwoma miejscami dziesiętnymi.The preceding line of code formats the value for Grades.Average() as a floating-point number with two decimal places.

Często może zajść potrzeba sformatowania ciągu utworzonego przy użyciu określonej kultury.Often, you may need to format the string produced using a specific culture. Możesz użyć faktu, że obiekt tworzony przez interpolację ciągu może być niejawnie konwertowany na System.FormattableString.You use the fact that the object produced by a string interpolation can be implicitly converted to System.FormattableString. FormattableString Wystąpienie zawiera ciąg formatu złożonego i wyniki oceny wyrażeń przed przekonwertowaniem ich na ciągi.The FormattableString instance contains the composite format string and the results of evaluating the expressions before converting them to strings. FormattableString.ToString(IFormatProvider) Użyj metody, aby określić kulturę podczas formatowania ciągu.Use the FormattableString.ToString(IFormatProvider) method to specify the culture when formatting a string. Poniższy przykład generuje ciąg przy użyciu kultury niemieckiej (de-DE).The following example produces a string using the German (de-DE) culture. (Domyślnie Kultura niemiecki używa znaku "," dla separatora dziesiętnego i znaku "." jako separatora tysięcy).(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"));

Aby rozpocząć pracę z interpolacją ciągów, zobacz Interpolacja ciągów C# w samouczku interaktywnym, artykuł interpolacji ciągów i Interpolacja ciągów w C# samouczku.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.

Filtry wyjątkówException filters

Filtry wyjątków są klauzulami, które określają, kiedy należy zastosować daną klauzulę catch.Exception Filters are clauses that determine when a given catch clause should be applied. Jeśli wyrażenie używane dla filtru wyjątków jest szacowane do true, klauzula catch wykonuje normalne przetwarzanie na wyjątek.If the expression used for an exception filter evaluates to true, the catch clause performs its normal processing on an exception. Jeśli wyrażenie zwróci falsewartość, catch klauzula jest pomijana.If the expression evaluates to false, then the catch clause is skipped. Jednym z nich jest badanie informacji o wyjątku, aby określić, czy catch klauzula może przetworzyć wyjątek: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";
        }
    }
}

nameof WyrażenieThe nameof expression

Wyrażenie nameof oblicza nazwę symbolu.The nameof expression evaluates to the name of a symbol. Jest to świetny sposób, aby uzyskać dostęp do narzędzi, gdy potrzebna jest nazwa zmiennej, właściwości lub pola elementu członkowskiego.It's a great way to get tools working whenever you need the name of a variable, a property, or a member field. Jednym z najpopularniejszych użycia programu nameof jest podanie nazwy symbolu, który spowodował wyjątek: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));

Innym zastosowaniem jest używanie aplikacji opartych na języku XAML INotifyPropertyChanged , które implementują interfejs: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 w blokach catch i finallyAwait in Catch and Finally blocks

C#5 miało kilka ograniczeń, w których można await umieścić wyrażenia.C# 5 had several limitations around where you could place await expressions. Za C# pomocą 6 można teraz używać await wyrażeń in catch i. finallyWith C# 6, you can now use await in catch or finally expressions. Jest to najczęściej używane w scenariuszach rejestrowania: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();
    }
}

Szczegóły implementacji umożliwiające dodanie await obsługi wewnątrz catch i finally klauzule upewnij się, że zachowanie jest zgodne z zachowaniem kodu synchronicznego.The implementation details for adding await support inside catch and finally clauses ensure that the behavior is consistent with the behavior for synchronous code. Gdy kod wykonywany w catch klauzuli or finally zgłasza, wykonanie szuka odpowiedniej catch klauzuli w następnym otaczającym bloku.When code executed in a catch or finally clause throws, execution looks for a suitable catch clause in the next surrounding block. Jeśli wystąpił bieżący wyjątek, ten wyjątek zostanie utracony.If there was a current exception, that exception is lost. Dzieje się tak samo w przypadku wyrażeń oczekujących finally w catch klauzulach i catch : odpowiednia wartość jest wyszukiwana, a obecny wyjątek, jeśli istnieje, zostanie utracony.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.

Uwaga

To zachowanie jest przyczyną, że zaleca się pisanie catch i finally klauzule uważnie, aby uniknąć wprowadzania nowych wyjątków.This behavior is the reason it's recommended to write catch and finally clauses carefully, to avoid introducing new exceptions.

Inicjuj kolekcje asocjacyjne przy użyciu indeksatorówInitialize associative collections using indexers

Inicjatory indeksów to jedna z dwóch funkcji, które sprawiają, że Inicjatory kolekcji są bardziej spójne z użyciem indeksu.Index Initializers is one of two features that make collection initializers more consistent with index usage. We wcześniejszych wersjach programu C#można było użyć inicjatorów kolekcji z kolekcjami stylów sekwencji, w Dictionary<TKey,TValue>tym, dodając nawiasy klamrowe wokół par klucz-wartość: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."}
};

Można ich używać z Dictionary<TKey,TValue> kolekcjami i innymi typami, w których dostępna Add Metoda akceptuje więcej niż jeden argument.You can use them with Dictionary<TKey,TValue> collections and other types where the accessible Add method accepts more than one argument. Nowa składnia obsługuje przypisanie przy użyciu indeksu do kolekcji: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."
};

Ta funkcja oznacza, że Kontenery asocjacyjne mogą być inicjowane przy użyciu składni podobnej do lokalizacji kontenerów sekwencji dla kilku wersji.This feature means that associative containers can be initialized using syntax similar to what's been in place for sequence containers for several versions.

Metody Add rozszerzające w inicjatorach kolekcjiExtension Add methods in collection initializers

Kolejną funkcją, która ułatwia inicjowanie kolekcji, jest możliwość użycia metody rozszerzenia dla Add metody.Another feature that makes collection initialization easier is the ability to use an extension method for the Add method. Ta funkcja została dodana do parzystości z Visual Basic.This feature was added for parity with Visual Basic. Ta funkcja jest najbardziej przydatna, gdy istnieje Klasa kolekcji niestandardowej, która ma metodę o innej nazwie do semantycznie Dodaj nowe elementy.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.

Ulepszone rozwiązanie przeciążaniaImproved overload resolution

Ta Ostatnia funkcja jest prawdopodobnie niezauważalna.This last feature is one you probably won't notice. Istnieją konstrukcje, w których Poprzednia wersja C# kompilatora mogła znaleźć pewne wywołania metody, które zawierają niejednoznaczne wyrażenia lambda.There were constructs where the previous version of the C# compiler may have found some method calls involving lambda expressions ambiguous. Rozważmy tę metodę:Consider this method:

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

We wcześniejszych wersjach programu C#wywołanie tej metody przy użyciu składni grupy metod nie powiedzie się:In earlier versions of C#, calling that method using the method group syntax would fail:

Task.Run(DoThings); 

Wcześniejszy kompilator nie może rozróżnić Task.Run(Action) prawidłowo Task.Run(Func<Task>())między i.The earlier compiler couldn't distinguish correctly between Task.Run(Action) and Task.Run(Func<Task>()). W poprzednich wersjach należy użyć wyrażenia lambda jako argumentu:In previous versions, you'd need to use a lambda expression as an argument:

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

C# 6 kompilator prawidłowo określa, że Task.Run(Func<Task>()) jest to lepszy wybór.The C# 6 compiler correctly determines that Task.Run(Func<Task>()) is a better choice.

Deterministyczne dane wyjściowe kompilatoraDeterministic compiler output

-deterministic Opcja instruuje kompilator, aby wytwarzał zestaw danych wyjściowych o identycznym bajcie dla kolejnych kompilacji tych samych plików źródłowych.The -deterministic option instructs the compiler to produce a byte-for-byte identical output assembly for successive compilations of the same source files.

Domyślnie każda kompilacja generuje unikatowe dane wyjściowe dla każdej kompilacji.By default, every compilation produces unique output on each compilation. Kompilator dodaje sygnaturę czasową i identyfikator GUID generowany na podstawie liczb losowych.The compiler adds a timestamp, and a GUID generated from random numbers. Użyj tej opcji, jeśli chcesz porównać dane wyjściowe bajty dla bajtów w celu zapewnienia spójności między kompilacjami.You use this option if you want to compare the byte-for-byte output to ensure consistency across builds.

Aby uzyskać więcej informacji, zobacz artykuł Opcja kompilatora-deterministyczna .For more information, see the -deterministic compiler option article.