Typy krotek języka C#C# tuple types

C# kolekcje są typy definiujące przy użyciu składni lekkiej.C# tuples are types that you define using a lightweight syntax. Zalety obejmują prostsze składni reguł podczas konwersji na podstawie liczby (nazywane kardynalności) i typy elementów i spójne zasady kopii, testy równości i przydziałów.The advantages include a simpler syntax, rules for conversions based on number (referred to as cardinality) and types of elements, and consistent rules for copies, equality tests, and assignments. Jako to z kompromisem krotek nie obsługują niektórych idiomy zorientowane obiektowo, skojarzone z dziedziczenia.As a tradeoff, tuples do not support some of the object-oriented idioms associated with inheritance. Możesz uzyskać omówienie w sekcji na krotek, co jest nowego w języku C# 7.0 artykułu.You can get an overview in the section on tuples in the What's new in C# 7.0 article.

W tym artykule dowiesz się, zasady języka krotkami w języku C# 7.0 i nowsze wersje, różne sposoby stosowania je i wstępną wskazówki na temat pracy z krotek.In this article, you'll learn the language rules governing tuples in C# 7.0 and later versions, different ways to use them, and initial guidance on working with tuples.

Uwaga

Nowe funkcje krotek wymagają ValueTuple typów.The new tuples features require the ValueTuple types. Należy dodać pakiet NuGet System.ValueTuple aby można było używać go na platformach, które nie zawierają typy.You must add the NuGet package System.ValueTuple in order to use it on platforms that do not include the types.

Jest to podobne do innych funkcji języka, które zależą od typów dostarczonych w ramach.This is similar to other language features that rely on types delivered in the framework. Przykłady obejmują async i await opierając się na INotifyCompletion interfejsu i LINQ, opierając się na IEnumerable<T>.Examples include async and await relying on the INotifyCompletion interface, and LINQ relying on IEnumerable<T>. Jednak mechanizm dostarczania jest zmieniają się wraz z .NET staje się coraz więcej platform niezależne.However, the delivery mechanism is changing as .NET is becoming more platform independent. .NET Framework mogą zawsze są dostarczane na ten sam cykl, jak kompilator języka.The .NET Framework may not always ship on the same cadence as the language compiler. Jeśli nowe funkcje języka, zależą od nowych typów, te typy są dostępne jako pakiety NuGet podczas dostarczania funkcji języka.When new language features rely on new types, those types will be available as NuGet packages when the language features ship. Ponieważ te nowe typy są dodawane do standardowego interfejsu API platformy .NET i dostarczane jako część ram, wymaganie pakietu NuGet zostaną usunięte.As these new types get added to the .NET Standard API and delivered as part of the framework, the NuGet package requirement will be removed.

Zacznijmy od przyczyny, dla których do dodawania nowych obsługi spójnej kolekcji.Let's start with the reasons for adding new tuple support. Metody zwracają jeden obiekt.Methods return a single object. Spójne kolekcje umożliwiają łatwiejsze pakowanie wielu wartości w tym pojedynczego obiektu.Tuples enable you to package multiple values in that single object more easily.

.NET Framework jest już ogólny Tuple klasy.The .NET Framework already has generic Tuple classes. Te klasy, ma dwa główne ograniczenia.These classes, however, had two major limitations. Dla jednego Tuple klasy o nazwie ich właściwości Item1, Item2i tak dalej.For one, the Tuple classes named their properties Item1, Item2, and so on. Te nazwy objęte żadne informacje semantyczne.Those names carry no semantic information. Korzystanie z tych Tuple typów nie obsługuje komunikacji znaczenie każdej właściwości.Using these Tuple types does not enable communicating the meaning of each of the properties. Nowe funkcje języka umożliwiają deklarowanie i użycie semantycznie znaczące nazwy elementów w krotce.The new language features enable you to declare and use semantically meaningful names for the elements in a tuple.

Tuple Klasy spowodować więcej problemów z wydajnością, ponieważ są to typy odwołań.The Tuple classes cause more performance concerns because they are reference types. Przy użyciu jednej z Tuple typy oznacza, że alokacja obiektów.Using one of the Tuple types means allocating objects. W warstwie gorąca ścieżkach przydzielanie wielu małych obiektów może mieć zauważalnego wpływu na wydajność aplikacji.On hot paths, allocating many small objects can have a measurable impact on your application's performance. W związku z tym, obsługa języków w krotek korzysta z nowym ValueTuple struktury.Therefore, the language support for tuples leverages the new ValueTuple structs.

Aby uniknąć tych braki, można utworzyć class lub struct do wykonania wielu elementów.To avoid those deficiencies, you could create a class or a struct to carry multiple elements. Niestety to więcej pracy i następuje ukrycie zgodną z planem projektu.Unfortunately, that's more work for you, and it obscures your design intent. Tworzenie struct lub class oznacza definiowania typu przy użyciu danych i zachowania.Making a struct or class implies that you are defining a type with both data and behavior. Wiele razy po prostu chcesz przechowywać wiele wartości w pojedynczy obiekt.Many times, you simply want to store multiple values in a single object.

Funkcje języka i ValueTuple struktury ogólne wymusić regułę, że nie można dodać każde zachowanie (metod) aby te typy krotek.The language features and the ValueTuple generic structs enforce the rule that you cannot add any behavior (methods) to these tuple types. Wszystkie ValueTuple typy są mutable struktury.All the ValueTuple types are mutable structs. Każde pole elementu członkowskiego jest polem publiczne.Each member field is a public field. Dzięki temu ich bardzo uproszczone.That makes them very lightweight. Jednak oznacza to, że nie należy używać krotek których niezmienności jest ważna.However, that means tuples should not be used where immutability is important.

Kolekcje są oba kontenery danych prostszy i bardziej elastyczne niż class i struct typów.Tuples are both simpler and more flexible data containers than class and struct types. Przyjrzyjmy się różnic.Let's explore those differences.

Nazwane i nienazwane krotkiNamed and unnamed tuples

ValueTuple Struktura zawiera pola o nazwie Item1, Item2, Item3i tak dalej podobne do właściwości zdefiniowane w istniejącym Tuple typów.The ValueTuple struct has fields named Item1, Item2, Item3, and so on, similar to the properties defined in the existing Tuple types. Te nazwy są tylko nazwy służy do nienazwane krotek.These names are the only names you can use for unnamed tuples. Wszystkie nazwy alternatywne pól do krotki nie zostanie określona, utworzono krotka bez nazwy:When you do not provide any alternative field names to a tuple, you've created an unnamed tuple:

var unnamed = ("one", "two");

Spójna kolekcja znajdująca się w poprzednim przykładzie została zainicjowana przy użyciu stałych literału i nie będzie nazwy elementów utworzonych za pomocą projekcje nazwę pola krotki w języku C# 7.1.The tuple in the previous example was initialized using literal constants and won't have element names created using tuple field name projections in C# 7.1.

Jednak podczas inicjowania krotki można użyć nowych funkcji języków, które zapewniają lepszą nazwy do każdego pola.However, when you initialize a tuple, you can use new language features that give better names to each field. Spowoduje to utworzenie o nazwie krotki.Doing so creates a named tuple. Nazwane krotek nadal mieć elementy o nazwie Item1, Item2, Item3 i tak dalej.Named tuples still have elements named Item1, Item2, Item3 and so on. Jednak mają one również synonimy dla każdej z tych elementów, które mają nazwane.But they also have synonyms for any of those elements that you have named. Możesz utworzyć nazwanego spójnej kolekcji przez określenie nazwy dla każdego elementu.You create a named tuple by specifying the names for each element. Jednym ze sposobów jest określane są nazwy w ramach inicjowania spójnej kolekcji:One way is to specify the names as part of the tuple initialization:

var named = (first: "one", second: "two");

Dodawanie tych synonimów są obsługiwane przez kompilator i język tak, aby można było używać o nazwie krotek skutecznie.These synonyms are handled by the compiler and the language so that you can use named tuples effectively. Środowiska IDE i edytorów mogą odczytywać te nazwy semantycznych przy użyciu interfejsów API Roslyn.IDEs and editors can read these semantic names using the Roslyn APIs. Elementy o nazwie krotki można się odwoływać przy użyciu tych nazw semantyczne w dowolnym miejscu tego samego zestawu.You can reference the elements of a named tuple by those semantic names anywhere in the same assembly. Kompilator zamienia nazwy zdefiniowany przez użytkownika za pomocą Item* odpowiedniki podczas generowania skompilowanych danych wyjściowych.The compiler replaces the names you've defined with Item* equivalents when generating the compiled output. Skompilowany Microsoft Intermediate Language (MSIL) nie zawiera nazwy, został przez Ciebie udzielony tych elementów.The compiled Microsoft Intermediate Language (MSIL) does not include the names you've given these elements.

Począwszy od języka C# 7.1 nazw pól dla krotki mogą być udostępniane ze zmiennych, używane do zainicjowania spójnej kolekcji.Beginning with C# 7.1, the field names for a tuple may be provided from the variables used to initialize the tuple. Jest to określane jako krotki rzutowanie inicjatorach.This is referred to as tuple projection initializers. Poniższy kod tworzy spójną kolekcję o nazwie accumulation z elementami count (liczba całkowita), a sum (wartość o podwójnej precyzji).The following code creates a tuple named accumulation with elements count (an integer), and sum (a double).

var sum = 12.5;
var count = 5;
var accumulation = (count, sum);

Kompilator musi komunikować się tymi nazwami utworzonych dla krotek, które są zwracane z właściwości lub metody publiczne.The compiler must communicate those names you created for tuples that are returned from public methods or properties. W takich przypadkach kompilator sam doda TupleElementNamesAttribute atrybutu w metodzie.In those cases, the compiler adds a TupleElementNamesAttribute attribute on the method. Ten atrybut zawiera TransformNames listy właściwości, która zawiera nazwy do poszczególnych elementów w spójnej kolekcji.This attribute contains a TransformNames list property that contains the names given to each of the elements in the tuple.

Uwaga

Narzędziami programistycznymi, takimi jak Visual Studio również odczytywać metadane i funkcji IntelliSense i inne funkcje za pomocą nazwy pól metadanych.Development Tools, such as Visual Studio, also read that metadata, and provide IntelliSense and other features using the metadata field names.

Należy zrozumieć podstawowe podstawowe informacje na temat nowych krotek i ValueTuple typu, aby zrozumieć zasady przypisywania o nazwie krotek do siebie nawzajem.It is important to understand these underlying fundamentals of the new tuples and the ValueTuple type in order to understand the rules for assigning named tuples to each other.

Inicjatory projekcji krotkiTuple projection initializers

Ogólnie rzecz biorąc krotki rzutowanie inicjatorach pracować przy użyciu nazwy zmiennej lub pola z po prawej stronie instrukcji inicjowania spójnej kolekcji.In general, tuple projection initializers work by using the variable or field names from the right-hand side of a tuple initialization statement. Jeśli jawna nazwa zostanie podany, który ma pierwszeństwo przed dowolną nazwę przewidywany.If an explicit name is given, that takes precedence over any projected name. Na przykład w inicjatorze następujące elementy są explicitFieldOne i explicitFieldTwo, a nie localVariableOne i localVariableTwo:For example, in the following initializer, the elements are explicitFieldOne and explicitFieldTwo, not localVariableOne and localVariableTwo:

var localVariableOne = 5;
var localVariableTwo = "some text";

var tuple = (explicitFieldOne: localVariableOne, explicitFieldTwo: localVariableTwo);

Dla dowolnego pola, w którym jawna nazwa nie zostanie podany przewidywany jest zastosowanie nazwy niejawne.For any field where an explicit name is not provided, an applicable implicit name is projected. Nie ma jawnie lub niejawnie, zapewnienie semantycznego nazwy.There is no requirement to provide semantic names, either explicitly or implicitly. Następujący inicjator ma nazw pól Item1, którego wartością jest 42 i stringContent, którego wartość to "Odpowiedź do wszystkich":The following initializer has field names Item1, whose value is 42 and stringContent, whose value is "The answer to everything":

var stringContent = "The answer to everything";
var mixedTuple = (42, stringContent);

Istnieją dwa warunki gdzie Release candidate nazwy pól nie są pokazane na pole spójnej kolekcji:There are two conditions where candidate field names are not projected onto the tuple field:

  1. Gdy nazwa Release candidate jest nazwą zarezerwowanych spójnej kolekcji.When the candidate name is a reserved tuple name. Przykłady obejmują Item3, ToString.Examples include Item3, ToString. lub Rest.or Rest.
  2. Gdy nazwa Release candidate jest duplikatem innej nazwy pola krotki jawnych lub niejawnych.When the candidate name is a duplicate of another tuple field name, either explicit or implicit.

Te warunki uniknąć niejednoznaczności.These conditions avoid ambiguity. Te nazwy mogłoby spowodować niejednoznaczność, gdyby były one używane jako nazwy pól dla pola w spójnej kolekcji.These names would cause an ambiguity if they were used as the field names for a field in a tuple. Żadna z tych warunków nie powodują błędy czasu kompilacji.Neither of these conditions cause compile-time errors. Zamiast tego elementy bez nazwy przewidywany nie ma nazwy semantycznego przewidywany dla nich.Instead, the elements without projected names do not have semantic names projected for them. W poniższych przykładach pokazano następujące warunki:The following examples demonstrate these conditions:

var ToString = "This is some text";
var one = 1;
var Item1 = 5;
var projections = (ToString, one, Item1);
// Accessing the first field:
Console.WriteLine(projections.Item1);
// There is no semantic name 'ToString'
// Accessing the second field:
Console.WriteLine(projections.one);
Console.WriteLine(projections.Item2);
// Accessing the third field:
Console.WriteLine(projections.Item3);
// There is no semantic name 'Item1`.

var pt1 = (X: 3, Y: 0);
var pt2 = (X: 3, Y: 4);

var xCoords = (pt1.X, pt2.X);
// There are no semantic names for the fields
// of xCoords. 

// Accessing the first field:
Console.WriteLine(xCoords.Item1);
// Accessing the second field:
Console.WriteLine(xCoords.Item2);

Tych sytuacji nie powodują błędy kompilatora, ponieważ byłoby istotną zmianę kod napisany w języku C# 7.0 podczas projekcji nazwę pola krotki nie były dostępne.These situations do not cause compiler errors because that would be a breaking change for code written with C# 7.0, when tuple field name projections were not available.

Równości i krotkiEquality and tuples

Począwszy od języka C# 7.3 krotki typy obsługi == i != operatorów.Beginning with C# 7.3, tuple types support the == and != operators. Te operatory działają przez porównanie każdy element członkowski argument po lewej stronie do każdego członka prawy argument w kolejności.These operators work by comparing each member of the left argument to each member of the right argument in order. Zwarcie tych porównań.These comparisons short-circuit. Przestaną one oceny członków, jak tylko jedną parę nie jest równa.They will stop evaluating members as soon as one pair is not equal. Poniższy kod przykłady użycia ==, ale dotyczą wszystkich reguł porównania !=.The following code examples use ==, but the comparison rules all apply to !=. Poniższy przykład kodu pokazuje porównania dla dwóch par liczb całkowitych:The following code example shows an equality comparison for two pairs of integers:

var left = (a: 5, b: 10);
var right = (a: 5, b: 10);
Console.WriteLine(left == right); // displays 'true'

Istnieje kilka reguł, które testy równość krotki bardziej wygodne.There are several rules that make tuple equality tests more convenient. Równość krotki wykonuje zniesione konwersje jedna z krotek czy krotki dopuszczającego wartość null, jak pokazano w poniższym kodzie:Tuple equality performs lifted conversions if one of the tuples is a nullable tuple, as shown in the following code:

var left = (a: 5, b: 10);
var right = (a: 5, b: 10);
(int a, int b)? nullableTuple = right;
Console.WriteLine(left == nullableTuple); // Also true

Równość krotki również wykonuje konwersje niejawne w każdym członku zarówno krotek.Tuple equality also performs implicit conversions on each member of both tuples. Obejmują one podniesionym konwersji, rozszerzające konwersje lub inne niejawne konwersje.These include lifted conversions, widening conversions, or other implicit conversions. Poniższe przykłady pokazują, czy liczba całkowita 2-krotka można porównać do długie 2-krotka z powodu niejawna konwersja liczbę całkowitą długie:The following examples show that an integer 2-tuple can be compared to a long 2-tuple because of the implicit conversion from integer to long:

// lifted conversions
var left = (a: 5, b: 10);
(int? a, int? b) nullableMembers = (5, 10);
Console.WriteLine(left == nullableMembers); // Also true

// converted type of left is (long, long)
(long a, long b) longTuple = (5, 10);
Console.WriteLine(left == longTuple); // Also true

// comparisons performed on (long, long) tuples
(long a, int b) longFirst = (5, 10);
(int a, long b) longSecond = (5, 10);
Console.WriteLine(longFirst == longSecond); // Also true

Nazwy elementów członkowskich krotki nie biorą udziału w testach dla równości.The names of the tuple members do not participate in tests for equality. Jednakże jeśli jeden z argumentów jest literałem jawne nazwy krotki, kompilator generuje ostrzeżenie CS8383, jeśli te nazwy są niezgodne nazwy to drugi operand.However, if one of the operands is a tuple literal with explicit names, the compiler generates warning CS8383 if those names do not match the names of the other operand. W przypadku, gdy oba operandy są literałach krotek to ostrzeżenie jest na prawy operand jak pokazano w poniższym przykładzie:In the case where both operands are tuple literals, the warning is on the right operand as shown in the following example:

(int a, string b) pair = (1, "Hello");
(int z, string y) another = (1, "Hello");
Console.WriteLine(pair == another); // true. Member names don't participate.
Console.WriteLine(pair == (z: 1, y: "Hello")); // warning: literal contains different member names

Na koniec krotek mogą zawierać zagnieżdżonych krotek.Finally, tuples may contain nested tuples. Równość krotki porównuje "kształt" Każdy argument przy użyciu zagnieżdżonych krotek, co pokazano w poniższym przykładzie:Tuple equality compares the "shape" of each operand through nested tuples as shown in the following example:

(int, (int, int)) nestedTuple = (1, (2, 3));
Console.WriteLine(nestedTuple == (1, (2, 3)) );

Jest to błąd czasu kompilacji, aby porównać dwie spójne kolekcje pod względem równości (lub nierówności) gdy mają różne kształty.It's a compile time error to compare two tuples for equality (or inequality) when they have different shapes. Kompilator nie będzie podejmować żadnych dekonstrukcja krotek zagnieżdżonych w celu porównania ich.The compiler won't attempt any deconstruction of nested tuples in order to compare them.

Przypisanie i krotkiAssignment and tuples

Język obsługuje przypisanie między typy krotek, które mają taką samą liczbę elementów, gdzie każdy element po prawej stronie mogą być niejawnie konwertowane do odpowiadającego mu elementu po lewej stronie.The language supports assignment between tuple types that have the same number of elements, where each right-hand side element can be implicitly converted to its corresponding left-hand side element. Inne konwersje nie są traktowane jako przydziałów.Other conversions aren't considered for assignments. Jest to błąd czasu kompilacji, można przypisać po jednej krotce na inny, gdy mają one różne kształty.It's a compile time error to assign one tuple to another when they have different shapes. Kompilator nie będzie podejmować żadnych dekonstrukcja krotek zagnieżdżonych Aby przypisać je.The compiler won't attempt any deconstruction of nested tuples in order to assign them. Przyjrzyjmy się rodzaje przypisania, które są dozwolone między typami spójnej kolekcji.Let's look at the kinds of assignments that are allowed between tuple types.

Należy wziąć pod uwagę te zmienne używane w następujących przykładach:Consider these variables used in the following examples:

// The 'arity' and 'shape' of all these tuples are compatible. 
// The only difference is the field names being used.
var unnamed = (42, "The meaning of life");
var anonymous = (16, "a perfect square");
var named = (Answer: 42, Message: "The meaning of life");
var differentNamed = (SecretConstant: 42, Label: "The meaning of life");

Pierwsze dwie zmienne unnamed i anonymous nie zawiera semantyczną nazw określone elementy.The first two variables, unnamed and anonymous do not have semantic names provided for the elements. Nazwy pól są Item1 i Item2.The field names are Item1 and Item2. Ostatnie dwie zmienne named i differentName semantycznego nazwach podanych elementów.The last two variables, named and differentName have semantic names given for the elements. Te dwie spójne kolekcje mają różne nazwy elementów.These two tuples have different names for the elements.

Wszystkie cztery krotek, te mają taką samą liczbę elementów (nazywane "Kardynalność") i typy te elementy są identyczne.All four of these tuples have the same number of elements (referred to as 'cardinality') and the types of those elements are identical. W związku z tym wszystkie te przydziały pracy:Therefore, all of these assignments work:

unnamed = named;

named = unnamed;
// 'named' still has fields that can be referred to
// as 'answer', and 'message':
Console.WriteLine($"{named.Answer}, {named.Message}");

// unnamed to unnamed:
anonymous = unnamed;

// named tuples.
named = differentNamed;
// The field names are not assigned. 'named' still has 
// fields that can be referred to as 'answer' and 'message':
Console.WriteLine($"{named.Answer}, {named.Message}");

// With implicit conversions:
// int can be implicitly converted to long
(long, string) conversion = named;

Należy zauważyć, że nazwy kolekcje nie są przypisane.Notice that the names of the tuples are not assigned. Wartości elementów są przypisywane w kolejności elementów w spójnej kolekcji.The values of the elements are assigned following the order of the elements in the tuple.

Krotki o różnych typach lub liczby elementów, nie są możliwe do przypisania:Tuples of different types or numbers of elements are not assignable:

// Does not compile.
// CS0029: Cannot assign Tuple(int,int,int) to Tuple(int, string)
var differentShape = (1, 2, 3);
named = differentShape;

Krotki jako wartości zwracane metodyTuples as method return values

Jednym z najbardziej typowych zastosowań krotek jest jako wartość zwracaną metody.One of the most common uses for tuples is as a method return value. Przejdźmy przykładem.Let's walk through one example. Należy wziąć pod uwagę tej metody, które oblicza odchylenie standardowe w sekwencji liczb:Consider this method that computes the standard deviation for a sequence of numbers:

public static double StandardDeviation(IEnumerable<double> sequence)
{
    // Step 1: Compute the Mean:
    var mean = sequence.Average();

    // Step 2: Compute the square of the differences between each number 
    // and the mean:
    var squaredMeanDifferences = from n in sequence
                                 select (n - mean) * (n - mean);
    // Step 3: Find the mean of those squared differences:
    var meanOfSquaredDifferences = squaredMeanDifferences.Average();

    // Step 4: Standard Deviation is the square root of that mean:
    var standardDeviation = Math.Sqrt(meanOfSquaredDifferences);
    return standardDeviation;
}

Uwaga

Te przykłady obliczeń odchylenie standardowe Niepoprawione próbki.These examples compute the uncorrected sample standard deviation. Wzór odchylenia standardowego poprawione próbki podzieleniu suma kwadratów różnic od średniej przez (n-1) zamiast N, jako Average metody rozszerzenia.The corrected sample standard deviation formula would divide the sum of the squared differences from the mean by (N-1) instead of N, as the Average extension method does. Zapoznaj się tekst statystyki, aby uzyskać więcej informacji na temat różnic między te formuły odchylenie standardowe.Consult a statistics text for more details on the differences between these formulas for standard deviation.

Powyższy kod poniżej Podręcznikowy formułę odchylenia standardowego.The preceding code follows the textbook formula for the standard deviation. Tworzy poprawną odpowiedź, ale jest nieefektywną implementację.It produces the correct answer, but it's an inefficient implementation. Ta metoda wylicza kolejność dwa razy: Jeden raz, aby wygenerować średnią i jeden raz, aby wygenerować średnia kwadratu różnicy średniej.This method enumerates the sequence twice: Once to produce the average, and once to produce the average of the square of the difference of the average. (Pamiętaj, że zapytania LINQ są obliczane z opóźnieniem, więc obliczania różnic od wartości średniej oraz średnią różnic sprawia, że tylko jedno wyliczenie).(Remember that LINQ queries are evaluated lazily, so the computation of the differences from the mean and the average of those differences makes only one enumeration.)

Istnieje alternatywny formuły, które oblicza odchylenie standardowe przy użyciu funkcji wyliczania tylko jednej sekwencji.There is an alternative formula that computes standard deviation using only one enumeration of the sequence. To obliczenie tworzy dwie wartości, jak wylicza kolejność: Suma wszystkich elementów w sekwencji, a sumę każdej wartości kwadrat:This computation produces two values as it enumerates the sequence: the sum of all items in the sequence, and the sum of the each value squared:

public static double StandardDeviation(IEnumerable<double> sequence)
{
    double sum = 0;
    double sumOfSquares = 0;
    double count = 0;

    foreach (var item in sequence)
    {
        count++;
        sum += item;
        sumOfSquares += item * item;
    }

    var variance = sumOfSquares - sum * sum / count;
    return Math.Sqrt(variance / count);
}

Ta wersja wylicza sekwencji dokładnie jeden raz.This version enumerates the sequence exactly once. Ale nie jest do ponownego wykorzystania kodu.But it's not reusable code. Jak możesz kontynuować pracę, przekonasz się, że wiele różnych obliczeń statystycznych używają liczba elementów w sekwencji, sumę sekwencji i suma kwadratów sekwencji.As you keep working, you'll find that many different statistical computations use the number of items in the sequence, the sum of the sequence, and the sum of the squares of the sequence. Przejdźmy Refaktoryzuj tę metodę i napisanie metody narzędzia, która tworzy wszystkie trzy tych wartości.Let's refactor this method and write a utility method that produces all three of those values. Wszystkie trzy wartości mogą być zwracane jako krotki.All three values can be returned as a tuple.

Zaktualizujmy tej metody, więc trzy wartości obliczonych podczas wyliczania są przechowywane w spójnej kolekcji.Let's update this method so the three values computed during the enumeration are stored in a tuple. Który tworzy tę wersję:That creates this version:

public static double StandardDeviation(IEnumerable<double> sequence)
{
    var computation = (Count: 0, Sum: 0.0, SumOfSquares: 0.0);

    foreach (var item in sequence)
    {
        computation.Count++;
        computation.Sum += item;
        computation.SumOfSquares += item * item;
    }

    var variance = computation.SumOfSquares - computation.Sum * computation.Sum / computation.Count;
    return Math.Sqrt(variance / computation.Count);
}

Pomoc techniczna dla programu Visual Studio Refactoring ułatwia wyodrębnić funkcja statystyki podstawowe do metody prywatnej.Visual Studio's Refactoring support makes it easy to extract the functionality for the core statistics into a private method. Zapewnia to private static metodę, która zwraca typ krotki z trzech wartości Sum, SumOfSquares, i Count:That gives you a private static method that returns the tuple type with the three values of Sum, SumOfSquares, and Count:

public static double StandardDeviation(IEnumerable<double> sequence)
{
    (int Count, double Sum, double SumOfSquares) computation = ComputeSumAndSumOfSquares(sequence);

    var variance = computation.SumOfSquares - computation.Sum * computation.Sum / computation.Count;
    return Math.Sqrt(variance / computation.Count);
}

private static (int Count, double Sum, double SumOfSquares) ComputeSumAndSumOfSquares(IEnumerable<double> sequence)
{
    var computation = (count: 0, sum: 0.0, sumOfSquares: 0.0);

    foreach (var item in sequence)
    {
        computation.count++;
        computation.sum += item;
        computation.sumOfSquares += item * item;
    }

    return computation;
}

Język umożliwia kilka więcej opcji, których można użyć, jeśli chcesz ręcznie wprowadzić kilka szybka edycja.The language enables a couple more options that you can use, if you want to make a few quick edits by hand. Najpierw należy użyć var deklaracji zainicjować krotki wynikiem ComputeSumAndSumOfSquares wywołania metody.First, you can use the var declaration to initialize the tuple result from the ComputeSumAndSumOfSquares method call. Możesz również utworzyć trzy zmienne dyskretnego wewnątrz ComputeSumAndSumOfSquares metody.You can also create three discrete variables inside the ComputeSumAndSumOfSquares method. Ostateczna wersja pokazano w poniższym kodzie:The final version is shown in the following code:

public static double StandardDeviation(IEnumerable<double> sequence)
{
    var computation = ComputeSumAndSumOfSquares(sequence);

    var variance = computation.SumOfSquares - computation.Sum * computation.Sum / computation.Count;
    return Math.Sqrt(variance / computation.Count);
}

private static (int Count, double Sum, double SumOfSquares) ComputeSumAndSumOfSquares(IEnumerable<double> sequence)
{
    double sum = 0;
    double sumOfSquares = 0;
    int count = 0;

    foreach (var item in sequence)
    {
        count++;
        sum += item;
        sumOfSquares += item * item;
    }

    return (count, sum, sumOfSquares);
}

Tej wersji ostatecznej może służyć do dowolnej metody, która potrzebuje tych trzech wartości lub dowolny podzbiór.This final version can be used for any method that needs those three values, or any subset of them.

Język obsługuje inne opcje zarządzania nazwy elementów w tych metodach zwracanie spójnej kolekcji.The language supports other options in managing the names of the elements in these tuple-returning methods.

Można usunąć nazwy pól z deklaracji zwracana wartość i zwrócić krotka bez nazwy:You can remove the field names from the return value declaration and return an unnamed tuple:

private static (double, double, int) ComputeSumAndSumOfSquares(IEnumerable<double> sequence)
{
    double sum = 0;
    double sumOfSquares = 0;
    int count = 0;

    foreach (var item in sequence)
    {
        count++;
        sum += item;
        sumOfSquares += item * item;
    }

    return (sum, sumOfSquares, count);
}

Pola tego krotki są nazywane Item1, Item2, i Item3.The fields of this tuple are named Item1, Item2, and Item3. Zalecane jest, aby podać semantycznego nazwy elementów krotek zwrócony z metody.It's recommended that you provide semantic names to the elements of tuples returned from methods.

Idiom innego, gdzie krotek może być przydatne jest podczas tworzenia zapytania LINQ.Another idiom where tuples can be useful is when you are authoring LINQ queries. Przewidywany wynik końcowy często zawiera niektóre, ale nie wszystkie właściwości obiekty są wybrane.The final projected result often contains some, but not all, of the properties of the objects being selected.

Wyniki zapytania będą tradycyjnie projektu sekwencję obiektów, które były typu anonimowego.You would traditionally project the results of the query into a sequence of objects that were an anonymous type. Wiele ograniczeń, przedstawione przede wszystkim, ponieważ typy anonimowe można nie zostaną w wygodny sposób mieć nazwy w typie zwracanym dla metody.That presented many limitations, primarily because anonymous types could not conveniently be named in the return type for a method. Za pomocą rozwiązania alternatywne object lub dynamic jako typ wyniku pochodzi z kosztami istotnie poprawiającą wydajność.Alternatives using object or dynamic as the type of the result came with significant performance costs.

Zwraca sekwencję krotki typu jest łatwe i nazwy i typy elementów są dostępne w czasie kompilacji, jak i za pomocą narzędzi IDE.Returning a sequence of a tuple type is easy, and the names and types of the elements are available at compile time and through IDE tools. Na przykład należy wziąć pod uwagę aplikację zadań do wykonania.For example, consider a ToDo application. Można zdefiniować klasę podobne do następujących czynności, aby reprezentować pojedynczy wpis na liście zadań do wykonania:You might define a class similar to the following to represent a single entry in the ToDo list:

public class ToDoItem
{
    public int ID { get; set; }
    public bool IsDone { get; set; }
    public DateTime DueDate { get; set; }
    public string Title { get; set; }
    public string Notes { get; set; }    
}

Twoje aplikacje mobilne mogą obsługiwać compact formularza bieżących elementów zadań do wykonania, która wyświetla tylko tytuł.Your mobile applications may support a compact form of the current ToDo items that only displays the title. Czy zapytania LINQ czyniłyby projekcji, zawiera tylko identyfikator i tytuł.That LINQ query would make a projection that includes only the ID and the title. Metody, która zwraca sekwencję krotek wyraża projektu oraz:A method that returns a sequence of tuples expresses that design well:

internal IEnumerable<(int ID, string Title)> GetCurrentItemsMobileList()
{
    return from item in AllItems
           where !item.IsDone
           orderby item.DueDate
           select (item.ID, item.Title);
}

Uwaga

W języku C# 7.1 projekcje krotki umożliwiają tworzenie nazwanego krotek, za pomocą elementów, w sposób podobny do nazw właściwości typów anonimowych.In C# 7.1, tuple projections enable you to create named tuples using elements, in a manner similar to the property naming in anonymous types. W powyższym kodzie select instrukcji w projekcji zapytań tworzy spójną kolekcją, która ma elementy ID i Title.In the above code, the select statement in the query projection creates a tuple that has elements ID and Title.

Krotki o nazwie może być częścią podpisu.The named tuple can be part of the signature. Dzięki temu kompilator i narzędzia IDE zapewniają statyczne, sprawdzanie, czy używasz wynik poprawnie.It lets the compiler and IDE tools provide static checking that you are using the result correctly. Nazwane krotki również przenosi informacje typu statycznego, więc nie ma potrzeby używania czas wykonywania kosztownych funkcji, takich jak odbicie lub dynamiczne powiązanie do pracy z wynikami.The named tuple also carries the static type information so there is no need to use expensive run time features like reflection or dynamic binding to work with the results.

DekonstrukcjaDeconstruction

Można rozpakować wszystkie elementy w krotce przez dekonstrukcja krotki zwracane przez metodę.You can unpackage all the items in a tuple by deconstructing the tuple returned by a method. Istnieją trzy różne sposoby dekonstrukcja krotek.There are three different approaches to deconstructing tuples. Po pierwsze można jawnie zadeklarować typ każdego pola, wewnątrz nawiasów, aby utworzyć zmienne dyskretnego dla poszczególnych elementów w spójnej kolekcji:First, you can explicitly declare the type of each field inside parentheses to create discrete variables for each of the elements in the tuple:

public static double StandardDeviation(IEnumerable<double> sequence)
{
    (int count, double sum, double sumOfSquares) = ComputeSumAndSumOfSquares(sequence);

    var variance = sumOfSquares - sum * sum / count;
    return Math.Sqrt(variance / count);
}

Niejawnie wpisane zmienne dla każdego pola w krotce można również zadeklarować za pomocą var — słowo kluczowe poza nawiasy:You can also declare implicitly typed variables for each field in a tuple by using the var keyword outside the parentheses:

public static double StandardDeviation(IEnumerable<double> sequence)
{
    var (sum, sumOfSquares, count) = ComputeSumAndSumOfSquares(sequence);

    var variance = sumOfSquares - sum * sum / count;
    return Math.Sqrt(variance / count);
}

Jest również użycie var — słowo kluczowe z dowolnego lub wszystkich deklaracji zmiennych wewnątrz nawiasów.It is also legal to use the var keyword with any, or all of the variable declarations inside the parentheses.

(double sum, var sumOfSquares, var count) = ComputeSumAndSumOfSquares(sequence);

Nie można użyć określonego typu przed nawiasem, nawet wtedy, gdy każde pole w spójnej kolekcji ma tego samego typu.You cannot use a specific type outside the parentheses, even if every field in the tuple has the same type.

Można dekonstruować krotki z istniejącej deklaracji także:You can deconstruct tuples with existing declarations as well:

public class Point
{
    public int X { get; set; }
    public int Y { get; set; }

    public Point(int x, int y) => (X, Y) = (x, y);
}

Ostrzeżenie

Nie można łączyć istniejące deklaracje za pomocą deklaracji wewnątrz nawiasów.You cannot mix existing declarations with declarations inside the parentheses. Na przykład następujące jest niedozwolone: (var x, y) = MyMethod();.For instance, the following is not allowed: (var x, y) = MyMethod();. Powoduje to błąd CS8184, ponieważ x jest zadeklarowana wewnątrz nawiasów i y wcześniej zadeklarowano gdzie indziej.This produces error CS8184 because x is declared inside the parentheses and y is previously declared elsewhere.

Dekonstrukcja typy zdefiniowane przez użytkownikaDeconstructing user-defined types

Może zostać zdekonstruowana dowolnego typu krotki, jak pokazano powyżej.Any tuple type can be deconstructed as shown above. Jest również łatwo włączyć dekonstrukcja z każdym typem zdefiniowanych przez użytkownika (klasy, struktury lub nawet interfejsów).It's also easy to enable deconstruction on any user-defined type (classes, structs, or even interfaces).

Autor typu można zdefiniować co najmniej jeden Deconstruct metod, które przypisać wartości do dowolnej liczby out zmienne reprezentujących elementy danych, które tworzą typu.The type author can define one or more Deconstruct methods that assign values to any number of out variables representing the data elements that make up the type. Na przykład następująca Person typ definiuje Deconstruct metodę, która deconstructs osoby do elementów reprezentujących imię i nazwisko:For example, the following Person type defines a Deconstruct method that deconstructs a person object into the elements representing the first name and last name:

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

    public Person(string first, string last)
    {
        FirstName = first;
        LastName = last;
    }

    public void Deconstruct(out string firstName, out string lastName)
    {
        firstName = FirstName;
        lastName = LastName;
    }
}

Metoda dekonstrukcji umożliwia przypisanie z Person na dwa ciągi znaków reprezentujące FirstName i LastName właściwości:The deconstruct method enables assignment from a Person to two strings, representing the FirstName and LastName properties:

var p = new Person("Althea", "Goodwin");
var (first, last) = p;

Można włączyć dekonstrukcja nawet w przypadku typów, które autorów.You can enable deconstruction even for types you did not author. Deconstruct Metoda może być metodą rozszerzenia, którą rozpakowywana członków dostępnych danych obiektu.The Deconstruct method can be an extension method that unpackages the accessible data members of an object. Poniżej przedstawiono przykład Student typu pochodną Person typu i metodę rozszerzenia, które deconstructs Student do trzech zmiennych, reprezentujący FirstName, LastNamei GPA:The example below shows a Student type, derived from the Person type, and an extension method that deconstructs a Student into three variables, representing the FirstName, the LastName, and the GPA:

public class Student : Person
{
    public double GPA { get; }
    public Student(string first, string last, double gpa) :
        base(first, last)
    {
        GPA = gpa;
    }
}

public static class Extensions
{
    public static void Deconstruct(this Student s, out string first, out string last, out double gpa)
    {
        first = s.FirstName;
        last = s.LastName;
        gpa = s.GPA;
    }
}

A Student ma teraz dostępne dwie Deconstruct metody: metoda rozszerzenia zadeklarowany dla Student typów i członek Person typu.A Student object now has two accessible Deconstruct methods: the extension method declared for Student types, and the member of the Person type. Znajdują się zarówno w zakresie i który umożliwia Student można zostać zdekonstruowana do dwóch zmiennych lub trzy.Both are in scope, and that enables a Student to be deconstructed into either two variables or three. Jeśli student można przypisać do trzech zmiennych, imienia, ostatni nazwę i GPA wszystkie zwracane są.If you assign a student to three variables, the first name, last name, and GPA are all returned. Jeśli przypiszesz student dwie zmienne, zwracane są tylko imię i nazwisko.If you assign a student to two variables, only the first name and the last name are returned.

var s1 = new Student("Cary", "Totten", 4.5);
var (fName, lName, gpa) = s1;

Należy zachować ostrożność, Definiowanie wielu Deconstruct metody w klasie lub hierarchii klas.You should be careful defining multiple Deconstruct methods in a class or a class hierarchy. Wiele Deconstruct metody, które mają taką samą liczbę out parametry szybko mogą powodować niejednoznaczności.Multiple Deconstruct methods that have the same number of out parameters can quickly cause ambiguities. Obiekty wywołujące nie można łatwo wywołać żądaną Deconstruct metody.Callers may not be able to easily call the desired Deconstruct method.

W tym przykładzie ma minimalne możliwości niejednoznaczne wywołanie ponieważ Deconstruct metodę Person ma dwa produkt wyjściowy parametrów, a Deconstruct metodę Student ma trzy.In this example, there is minimal chance for an ambiguous call because the Deconstruct method for Person has two output parameters, and the Deconstruct method for Student has three.

Operatory dekonstrukcja nie biorą udziału w testowaniu równości.Deconstruction operators do not participate in testing equality. Poniższy przykład generuje błąd kompilatora CS0019:The following example generates compiler error CS0019:

Person p = new Person("Althea", "Goodwin");
if (("Althea", "Goodwin") == p)
    Console.WriteLine(p);

Deconstruct Metoda można przekonwertować Person obiektu p do spójnych kolekcji zawierający dwa ciągi, ale nie ma zastosowania w kontekście testy równości.The Deconstruct method could convert the Person object p to a tuple containing two strings, but it is not applicable in the context of equality tests.

WniosekConclusion

Nowy język i biblioteki obsługę krotek nazwane sprawia, że znacznie łatwiej jest pracować z projektami używające struktur danych, które przechowują wiele elementów, ale nie definiują zachowania, tak jak klas i struktur.The new language and library support for named tuples makes it much easier to work with designs that use data structures that store multiple elements but do not define behavior, as classes and structs do. Jest to łatwa i zwięzła, aby używać spójnych kolekcji dla tych typów.It's easy and concise to use tuples for those types. Możesz korzystać ze wszystkich zalet sprawdzania typu statycznego, bez konieczności tworzenia typów przy użyciu bardziej szczegółowy class lub struct składni.You get all the benefits of static type checking, without needing to author types using the more verbose class or struct syntax. Mimo to najbardziej przydatny w przypadku metod narzędzie, które są private, lub internal.Even so, they are most useful for utility methods that are private, or internal. Tworzenie typów zdefiniowanych przez użytkownika, albo class lub struct typów podczas publicznej metody zwracają wartość, która ma wiele elementów.Create user-defined types, either class or struct types when your public methods return a value that has multiple elements.