Neuerungen von C# 7.0 bis C# 7.3What's new in C# 7.0 through C# 7.3
Von C# 7.0 bis C# 7.3 wurden zahlreiche Features für und inkrementelle Verbesserungen an den Entwicklungsfunktionen von C# eingeführt.C# 7.0 through C# 7.3 brought a number of features and incremental improvements to your development experience with C#. In diesem Artikel erhalten Sie einen Überblick über die neuen Sprachfeatures und Compileroptionen.This article provides an overview of the new language features and compiler options. In den Beschreibungen wird das Verhalten für C# 7.3 erläutert. Dabei handelt es sich um die aktuelle Version, die für auf dem .NET Framework basierende Anwendungen unterstützt wird.The descriptions describe the behavior for C# 7.3, which is the most recent version supported for .NET Framework-based applications.
Das Konfigurationselement für die Sprachversionsauswahl wurde im Rahmen von C# 7.1 hinzugefügt. Damit können Sie die Compilersprachenversion in Ihrer Projektdatei angeben.The language version selection configuration element was added with C# 7.1, which enables you to specify the compiler language version in your project file.
Von C# 7.0 bis C# 7.3 wurden der C#-Sprache die folgenden Features und Designs hinzugefügt:C# 7.0-7.3 adds these features and themes to the C# language:
- Tupel und VerwerfenTuples and discards
- Sie können einfache, unbenannte Typen erstellen, die mehrere öffentliche Felder enthalten.You can create lightweight, unnamed types that contain multiple public fields. Compiler und IDE-Tools kennen die Semantik dieser Typen.Compilers and IDE tools understand the semantics of these types.
- Ausschussvariablen (discards) sind temporäre, lesegeschützte Variablen, die in Zuweisungen verwendet werden, wenn der zugewiesene Wert nicht weiter interessiert.Discards are temporary, write-only variables used in assignments when you don't care about the value assigned. Sie eignen sich besonders zum Dekonstruieren von Tupeln und benutzerdefinierten Typen sowie beim Aufrufen von Methoden mit
out
-Parametern.They're most useful when deconstructing tuples and user-defined types, as well as when calling methods without
parameters.
- MustervergleichPattern Matching
- Sie können Verzweigungslogik basierend auf beliebigen Typen und Werten der Member dieser Typen erstellen.You can create branching logic based on arbitrary types and values of the members of those types.
async
Main
-Methodeasync
Main
method- Der Einstiegspunkt für eine Anwendung kann über den Modifizierer
async
verfügen.The entry point for an application can have theasync
modifier.
- Der Einstiegspunkt für eine Anwendung kann über den Modifizierer
- Lokale FunktionenLocal Functions
- Sie können Funktionen innerhalb von anderen Funktionen verschachteln, um deren Bereich und Sichtbarkeit zu beschränken.You can nest functions inside other functions to limit their scope and visibility.
- Mehr AusdruckskörpermemberMore expression-bodied members
- Die Liste der Member, die mithilfe von Ausdrücken erstellt werden können, ist länger geworden.The list of members that can be authored using expressions has grown.
throw
-Ausdrückethrow
Expressions- Sie können Ausnahmen in Codekonstrukten auslösen, die vorher nicht zulässig waren, da
throw
eine Anweisung war.You can throw exceptions in code constructs that previously weren't allowed becausethrow
was a statement.
- Sie können Ausnahmen in Codekonstrukten auslösen, die vorher nicht zulässig waren, da
default
Literale Ausdrückedefault
literal expressions- Sie können literale Standardausdrücke in Standardwertausdrücken verwenden, wenn der Zieltyp abgeleitet werden kann.You can use default literal expressions in default value expressions when the target type can be inferred.
- Verbesserung der numerischen literalen SyntaxNumeric literal syntax improvements
- Neue Token verbessern die Lesbarkeit für numerische Konstanten.New tokens improve readability for numeric constants.
out
Variablenout
variables- Sie können
out
-Werte als Inlineargumente für die Methode deklarieren, wenn sie verwendet werden.You can declareout
values inline as arguments to the method where they're used.
- Sie können
- Nicht schließende benannte ArgumenteNon-trailing named arguments
- Positionelle Argumente können auf benannte Argumente folgen.Named arguments can be followed by positional arguments.
private protected
-Zugriffsmodifiziererprivate protected
access modifier- Der
private protected
-Zugriffsmodifizierer ermöglicht den Zugriff für abgeleitete Klassen innerhalb der gleichen Assembly.Theprivate protected
access modifier enables access for derived classes in the same assembly.
- Der
- Verbesserte ÜberladungsauflösungImproved overload resolution
- Neue Regeln sorgen nun für die Auflösung von Ambiguitäten bei Überladungsauflösungen.New rules to resolve overload resolution ambiguity.
- Techniken zum Schreiben von sicherem, effizientem CodeTechniques for writing safe efficient code
- Eine Kombination aus Verbesserungen der Syntax, die das Arbeiten mit Werttypen mithilfe von Verweissemantik ermöglichen.A combination of syntax improvements that enable working with value types using reference semantics.
Schließlich verfügt der Compiler über neue Optionen:Finally, the compiler has new options:
-refout
und-refonly
, wodurch die Erstellung von Referenzassemblys gesteuert wird.-refout
and-refonly
that control reference assembly generation.-publicsign
, um das Signieren von Assemblys durch Open Source Software (OSS) zu ermöglichen.-publicsign
to enable Open Source Software (OSS) signing of assemblies.-pathmap
, um eine Zuordnung für Quellverzeichnisse bereitzustellen.-pathmap
to provide a mapping for source directories.
Dieser Artikel enthält im Folgenden eine Übersicht über die einzelnen Funktionen.The remainder of this article provides an overview of each feature. Sie werden die Hintergründe sowie die Syntax jedes einzelnen Features kennenlernen.For each feature, you'll learn the reasoning behind it and the syntax. Sie können sich diese Funktionen in unserer Umgebung mit dem globalen dotnet try
-Tool näher ansehen:You can explore these features in your environment using the dotnet try
global tool:
- Installieren Sie das globale dotnet-try-Tool.Install the dotnet-try global tool.
- Klonen Sie das dotnet/try-samples-Repository.Clone the dotnet/try-samples repository.
- Legen Sie das aktuelle Verzeichnis auf das Unterverzeichnis csharp7 für das try-samples-Repository fest.Set the current directory to the csharp7 subdirectory for the try-samples repository.
- Führen Sie aus
dotnet try
.Rundotnet try
.
Tupel und VerwerfenTuples and discards
C# bietet eine umfangreiche Syntax für Klassen und Strukturen, die verwendet wird, um Ihre Entwurfsabsicht zu erläutern.C# provides a rich syntax for classes and structs that is used to explain your design intent. Aber manchmal erfordert diese umfangreiche Syntax zusätzliche Arbeit mit minimalem Nutzen.But sometimes that rich syntax requires extra work with minimal benefit. Möglicherweise schreiben Sie häufig Methoden, die eine einfache Struktur erfordern, die mehr als ein Datenelement enthält.You may often write methods that need a simple structure containing more than one data element. Zur Unterstützung dieser Szenarios wurden C# Tupel hinzugefügt.To support these scenarios tuples were added to C#. Tupel sind einfache Datenstrukturen, die mehrere Felder zur Darstellung der Datenmember enthalten.Tuples are lightweight data structures that contain multiple fields to represent the data members. Die Felder werden nicht überprüft, und Sie können keine eigenen Methoden definieren.The fields aren't validated, and you can't define your own methods. C#-Tupeltypen unterstützen ==
und !=
.C# tuple types support ==
and !=
. Weitere Informationen.For more information.
Hinweis
Tupel waren schon vor C# 7.0 verfügbar, sie waren jedoch ineffizient und hatten keine Sprachunterstützung.Tuples were available before C# 7.0, but they were inefficient and had no language support. Das brachte mit sich, dass auf Tupelelemente nur als Item1
, Item2
usw. verwiesen werden konnte.This meant that tuple elements could only be referenced as Item1
, Item2
and so on. Mit C# 7.0 wird Sprachunterstützung für Tupel eingeführt, wodurch semantische Namen für die Felder eines Tupels mit Einsatz neuer, effizienterer Tupeltypen möglich werden.C# 7.0 introduces language support for tuples, which enables semantic names for the fields of a tuple using new, more efficient tuple types.
Sie können ein Tupel erstellen, indem Sie jedem Member einen Wert zuweisen und ihnen optional auch semantische Namen bereitstellen:You can create a tuple by assigning a value to each member, and optionally providing semantic names to each of the members of the tuple:
(string Alpha, string Beta) namedLetters = ("a", "b");
Console.WriteLine($"{namedLetters.Alpha}, {namedLetters.Beta}");
Das namedLetters
-Tupel enthält Felder, die als Alpha
und Beta
bezeichnet werden.The namedLetters
tuple contains fields referred to as Alpha
and Beta
. Diese Namen bestehen nur zur Kompilierzeit und werden nicht beibehalten, wenn das Tupel beispielsweise zur Laufzeit mithilfe von Reflektion untersucht wird.Those names exist only at compile time and aren't preserved, for example when inspecting the tuple using reflection at run time.
In einer Tupelzuweisung können Sie auch die Namen der Felder auf der rechten Seite der Zuweisung angeben:In a tuple assignment, you can also specify the names of the fields on the right-hand side of the assignment:
var alphabetStart = (Alpha: "a", Beta: "b");
Console.WriteLine($"{alphabetStart.Alpha}, {alphabetStart.Beta}");
Manchmal möchten Sie vielleicht die Member eines Tupels entpacken, die von einer Methode zurückgegeben wurden.There may be times when you want to unpackage the members of a tuple that were returned from a method. Sie können dazu für jeden Wert im Tupel separate Variablen deklarieren.You can do that by declaring separate variables for each of the values in the tuple. Das Auspacken wird als Dekonstruieren des Tupels bezeichnet:This unpackaging is called deconstructing the tuple:
(int max, int min) = Range(numbers);
Console.WriteLine(max);
Console.WriteLine(min);
Sie können auch eine ähnliche Dekonstruktion für alle Typen in .NET bereitstellen.You can also provide a similar deconstruction for any type in .NET. Schreiben Sie eine Deconstruct
-Methode als Member der Klasse.You write a Deconstruct
method as a member of the class. Diese Deconstruct
-Methode bietet eine Reihe von out
-Argumenten für jede der Eigenschaften, die Sie extrahieren möchten.That Deconstruct
method provides a set of out
arguments for each of the properties you want to extract. Berücksichtigen Sie diese Point
-Klasse, die eine Dekonstruktionsmethode bereitstellt, die die X
- und Y
-Koordinaten extrahiert:Consider this Point
class that provides a deconstructor method that extracts the X
and Y
coordinates:
public class Point
{
public Point(double x, double y)
=> (X, Y) = (x, y);
public double X { get; }
public double Y { get; }
public void Deconstruct(out double x, out double y) =>
(x, y) = (X, Y);
}
Sie können die einzelnen Felder extrahieren, indem Sie einem Point
ein Tupel zuweisen:You can extract the individual fields by assigning a Point
to a tuple:
var p = new Point(3.14, 2.71);
(double X, double Y) = p;
Wenn Sie einen Tupel initialisieren, sind die Variablen, die für die rechte Seite der Zuweisung verwendet werden, oft dieselben, wie die Namen, die Sie den Tupelelementen geben möchten. Die Namen von Tupelelementen können von den Variablen abgeleitet werden, die zum Initialisieren der Tupel verwendet werden:Many times when you initialize a tuple, the variables used for the right side of the assignment are the same as the names you'd like for the tuple elements: The names of tuple elements can be inferred from the variables used to initialize the tuple:
int count = 5;
string label = "Colors used in the map";
var pair = (count, label); // element names are "count" and "label"
Weitere Informationen zu diesem Feature finden Sie im Artikel Tupeltypen.You can learn more about this feature in the Tuple types article.
Beim Dekonstruieren eines Tupels oder dem Aufrufen einer Methode mit out
-Parametern sind Sie gezwungen, eine Variable zu definieren, deren Wert Sie nicht interessiert und die Sie nicht zu verwenden beabsichtigen.Often when deconstructing a tuple or calling a method with out
parameters, you're forced to define a variable whose value you don't care about and don't intend to use. C# verfügt jetzt über Unterstützung für Ausschussvariablen (discards), um diesem Szenario Rechnung zu tragen.C# adds support for discards to handle this scenario. Eine Ausschussvariable ist eine lesegeschützte Variable mit dem Namen _
(dem Unterstrichzeichen); Sie können der einzelnen Variablen alle Werte zuweisen, die Sie verwerfen möchten.A discard is a write-only variable whose name is _
(the underscore character); you can assign all of the values that you intend to discard to the single variable. Eine Ausschussvariable ist wie eine nicht zugewiesene Variable; abgesehen von der Zuweisungsanweisung kann die Ausschussvariable nicht in Code verwendet werden.A discard is like an unassigned variable; apart from the assignment statement, the discard can't be used in code.
Ausschussvariablen werden in den folgenden Szenarien unterstützt:Discards are supported in the following scenarios:
- Beim Dekonstruieren von Tupeln oder benutzerdefinierten Typen.When deconstructing tuples or user-defined types.
- Beim Aufrufen von Methoden mit out-Parametern.When calling methods with out parameters.
- In einem Musterabgleichsvorgang mit den Anweisungen is und switch.In a pattern matching operation with the is and switch statements.
- Als eigenständiger Bezeichner, wenn Sie den Wert einer Zuweisung explizit als Ausschuss kennzeichnen möchten.As a standalone identifier when you want to explicitly identify the value of an assignment as a discard.
Das folgende Beispiel definiert eine QueryCityDataForYears
-Methode, die ein 6-Tupel zurückgibt, das ein Datum für eine Stadt für zwei verschiedene Jahre enthält.The following example defines a QueryCityDataForYears
method that returns a 6-tuple that contains data for a city for two different years. Der Methodenaufruf im Beispiel befasst sich nur mit den zwei Bevölkerungswerten, die von der Methode zurückgegeben werden und behandelt so die verbleibenden Werte im Tupel beim Dekonstruieren des Tupels als Ausschuss.The method call in the example is concerned only with the two population values returned by the method and so treats the remaining values in the tuple as discards when it deconstructs the tuple.
using System;
using System.Collections.Generic;
public class Example
{
public static void Main()
{
var (_, _, _, pop1, _, pop2) = QueryCityDataForYears("New York City", 1960, 2010);
Console.WriteLine($"Population change, 1960 to 2010: {pop2 - pop1:N0}");
}
private static (string, double, int, int, int, int) QueryCityDataForYears(string name, int year1, int year2)
{
int population1 = 0, population2 = 0;
double area = 0;
if (name == "New York City")
{
area = 468.48;
if (year1 == 1960)
{
population1 = 7781984;
}
if (year2 == 2010)
{
population2 = 8175133;
}
return (name, area, year1, population1, year2, population2);
}
return ("", 0, 0, 0, 0, 0);
}
}
// The example displays the following output:
// Population change, 1960 to 2010: 393,149
Weitere Informationen finden Sie unter Ausschuss.For more information, see Discards.
MusterabgleichPattern matching
Beim Musterabgleich handelt es sich um mehrere Features, die neue Möglichkeiten eröffnen, Ablaufsteuerung in Ihrem Code auszudrücken.Pattern matching is a set of features that enable new ways to express control flow in your code. Sie können Variablen nach Typ, Werten oder den Werten ihrer Eigenschaften testen.You can test variables for their type, values or the values of their properties. Dieses Vorgehen sorgt für einen besser lesbaren Codeflow.These techniques create more readable code flow.
Mustervergleich unterstützt is
-Ausdrücke und switch
-Ausdrücke.Pattern matching supports is
expressions and switch
expressions. Jeder davon ermöglicht das Überprüfen eines Objekts und dessen Eigenschaften, um zu bestimmen, ob das Objekt dem gesuchten Muster entspricht.Each enables inspecting an object and its properties to determine if that object satisfies the sought pattern. Sie verwenden das when
-Schlüsselwort, um zusätzliche Regeln für das Muster anzugeben.You use the when
keyword to specify additional rules to the pattern.
Der Musterausdruck is
erweitert den vertrauten is
-Operator, um eine Abfrage zum Typ eines Objekts auszuführen und das Ergebnis in einer Anweisung zuzuweisen.The is
pattern expression extends the familiar is
operator to query an object about its type and assign the result in one instruction. Der folgende Code überprüft, ob es sich bei einer Variablen um einen int
-Wert handelt und fügt sie, wenn dies der Fall ist, der aktuellen Summe hinzu:The following code checks if a variable is an int
, and if so, adds it to the current sum:
if (input is int count)
sum += count;
Das vorausgegangene kleine Beispiel verdeutlicht die Verbesserungen des is
-Ausdrucks.The preceding small example demonstrates the enhancements to the is
expression. Sie können für Wert- und Verweistypen testen und das erfolgreiche Ergebnis einer neuen Variable des richtigen Typs zuweisen.You can test against value types as well as reference types, and you can assign the successful result to a new variable of the correct type.
Der Switch-Vergleichsausdruck verfügt über eine vertraute Syntax basierend auf der switch
-Anweisung, die bereits Teil der C#-Sprache ist.The switch match expression has a familiar syntax, based on the switch
statement already part of the C# language. Die aktualisierte Switch-Anweisung verfügt über mehrere neue Konstrukte:The updated switch statement has several new constructs:
- Der maßgebliche Typ eines
switch
-Ausdrucks ist nicht mehr beschränkt auf ganzzahlige Typen,Enum
-Typen,string
oder einen Nullable-Typ, der einem dieser Typen entspricht.The governing type of aswitch
expression is no longer restricted to integral types,Enum
types,string
, or a nullable type corresponding to one of those types. Es kann jeder Typ verwendet werden.Any type may be used. - Sie können den Typ des
switch
-Ausdrucks in jedercase
-Bezeichnung testen.You can test the type of theswitch
expression in eachcase
label. Sie können diesem Typ wie schon beimis
-Ausdruck eine neue Variable zuweisen.As with theis
expression, you may assign a new variable to that type. - Wenn Sie die Bedingungen für diese Variable weiter testen möchten, können Sie eine
when
-Klausel hinzufügen.You may add awhen
clause to further test conditions on that variable. - Die Reihenfolge der
case
-Bezeichnungen ist hierbei entscheidend.The order ofcase
labels is now important. Die erste Verzweigung, für die eine Übereinstimmung gefunden wird, wird ausgeführt. Alle weiteren werden übersprungen.The first branch to match is executed; others are skipped.
Im folgenden Code werden diese Funktionen veranschaulicht:The following code demonstrates these new features:
public static int SumPositiveNumbers(IEnumerable<object> sequence)
{
int sum = 0;
foreach (var i in sequence)
{
switch (i)
{
case 0:
break;
case IEnumerable<int> childSequence:
{
foreach(var item in childSequence)
sum += (item > 0) ? item : 0;
break;
}
case int n when n > 0:
sum += n;
break;
case null:
throw new NullReferenceException("Null found in sequence");
default:
throw new InvalidOperationException("Unrecognized type");
}
}
return sum;
}
case 0:
ist das vertraute Konstantenmuster.case 0:
is the familiar constant pattern.case IEnumerable<int> childSequence:
ist ein Typmuster.case IEnumerable<int> childSequence:
is a type pattern.case int n when n > 0:
ist ein Typmuster mit einer zusätzlichenwhen
-Bedingung.case int n when n > 0:
is a type pattern with an additionalwhen
condition.case null:
ist das NULL-Muster.case null:
is the null pattern.default:
ist die vertraute Standardanfrage.default:
is the familiar default case.
Ab C# 7.1 kann der Musterausdruck für is
und das switch
-Typmuster den Typ eines generischen Typparameters haben.Beginning with C# 7.1, the pattern expression for is
and the switch
type pattern may have the type of a generic type parameter. Dies kann sehr nützlich sein, wenn Sie Typen überprüfen, die entweder struct
- oder class
-Typen sein können, und Sie Boxing vermeiden möchten.This can be most useful when checking types that may be either struct
or class
types, and you want to avoid boxing.
Weitere Informationen zum Mustervergleich finden Sie unter Pattern Matching in C# (Mustervergleich in C#).You can learn more about pattern matching in Pattern Matching in C#.
Async MainAsync main
Mithilfe einer async main-Methode können Sie await
in Ihrer Main
-Methode verwenden.An async main method enables you to use await
in your Main
method. Vorher hätten Sie das Folgende schreiben müssen:Previously you would need to write:
static int Main()
{
return DoAsyncWork().GetAwaiter().GetResult();
}
Nun können Sie das Folgende schreiben:You can now write:
static async Task<int> Main()
{
// This could also be replaced with the body
// DoAsyncWork, including its await expressions:
return await DoAsyncWork();
}
Wenn Ihr Programm keinen Exitcode zurückgibt, können Sie eine Main
-Methode deklarieren, die einen Task zurückgibt:If your program doesn't return an exit code, you can declare a Main
method that returns a Task:
static async Task Main()
{
await SomeAsyncMethod();
}
Ausführliche Informationen finden Sie unter Async Main im Programmierhandbuch.You can read more about the details in the async main article in the programming guide.
Lokale FunktionenLocal functions
Viele Entwürfe für Klassen enthalten Methoden, die nur von einer Stelle aufgerufen werden.Many designs for classes include methods that are called from only one location. Durch diese zusätzlichen privaten Methoden bleibt jede Methode klein und konzentriert.These additional private methods keep each method small and focused. Mit lokalen Funktionen können Sie Methoden innerhalb des Kontexts einer anderen Methode deklarieren.Local functions enable you to declare methods inside the context of another method. So können Leser der Klasse leichter erkennen, dass die lokale Methode nur aus dem Kontext aufgerufen wird, in dem sie deklariert wird.Local functions make it easier for readers of the class to see that the local method is only called from the context in which it is declared.
Es gibt zwei häufige Anwendungsfälle für lokale Funktionen: öffentliche Iteratormethoden und öffentliche asynchrone Methoden.There are two common use cases for local functions: public iterator methods and public async methods. Beide Arten von Methoden generieren Code, der Fehler später meldet, als Programmierer erwarten würden.Both types of methods generate code that reports errors later than programmers might expect. Bei Iteratormethoden werden Ausnahmen nur festgestellt, wenn Code aufgerufen wird, der die zurückgegebene Sequenz auflistet.In iterator methods, any exceptions are observed only when calling code that enumerates the returned sequence. Bei asynchronen Methoden werden Ausnahmen nur festgestellt, wenn der zurückgegebene Task
-Wert erwartet wird.In async methods, any exceptions are only observed when the returned Task
is awaited. Im folgenden Beispiel wird veranschaulicht, wie mithilfe einer lokalen Funktion die Überprüfung der Parameter von der Iteratorimplementierung getrennt wird:The following example demonstrates separating parameter validation from the iterator implementation using a local function:
public static IEnumerable<char> AlphabetSubset3(char start, char end)
{
if (start < 'a' || start > 'z')
throw new ArgumentOutOfRangeException(paramName: nameof(start), message: "start must be a letter");
if (end < 'a' || end > 'z')
throw new ArgumentOutOfRangeException(paramName: nameof(end), message: "end must be a letter");
if (end <= start)
throw new ArgumentException($"{nameof(end)} must be greater than {nameof(start)}");
return alphabetSubsetImplementation();
IEnumerable<char> alphabetSubsetImplementation()
{
for (var c = start; c < end; c++)
yield return c;
}
}
Das gleiche Verfahren kann mit async
-Methoden eingesetzt werden, um sicherzustellen, dass Ausnahmen aufgrund der Argumentüberprüfung ausgelöst werden, bevor die asynchrone Arbeit beginnt:The same technique can be employed with async
methods to ensure that exceptions arising from argument validation are thrown before the asynchronous work begins:
public Task<string> PerformLongRunningWork(string address, int index, string name)
{
if (string.IsNullOrWhiteSpace(address))
throw new ArgumentException(message: "An address is required", paramName: nameof(address));
if (index < 0)
throw new ArgumentOutOfRangeException(paramName: nameof(index), message: "The index must be non-negative");
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException(message: "You must supply a name", paramName: nameof(name));
return longRunningWorkImplementation();
async Task<string> longRunningWorkImplementation()
{
var interimResult = await FirstWork(address);
var secondResult = await SecondStep(index, name);
return $"The results are {interimResult} and {secondResult}. Enjoy.";
}
}
Diese Syntax wird jetzt unterstützt:This syntax is now supported:
[field: SomeThingAboutFieldAttribute]
public int SomeProperty { get; set; }
Das Attribut SomeThingAboutFieldAttribute
wird auf das vom Compiler generierte Unterstützungsfeld für SomeProperty
angewendet.The attribute SomeThingAboutFieldAttribute
is applied to the compiler generated backing field for SomeProperty
. Weitere Informationen finden Sie unter attributes im C#-Programmierhandbuch.For more information, see attributes in the C# programming guide.
Hinweis
Einige der Entwürfe, die von lokalen Funktionen unterstützt werden, können auch mithilfe von Lambdaausdrücken erreicht werden.Some of the designs that are supported by local functions can also be accomplished using lambda expressions. Weitere Informationen finden Sie unter Lokale Funktionen im Vergleich zu Lambdaausdrücken.For more information, see Local functions vs. lambda expressions.
Mehr AusdruckskörpermemberMore expression-bodied members
In C# 6 wurden Ausdruckskörpermember für Memberfunktionen und schreibgeschützte Eigenschaften eingeführt.C# 6 introduced expression-bodied members for member functions and read-only properties. Mit C# 7.0 werden die zulässigen Member erweitert, die als Ausdrücke implementiert werden können.C# 7.0 expands the allowed members that can be implemented as expressions. In C# 7.0 können Sie Konstruktoren, Finalizer sowie get
- und set
-Zugriffsmethoden für Eigenschaften und Indexer implementieren.In C# 7.0, you can implement constructors, finalizers, and get
and set
accessors on properties and indexers. Der folgende Code zeigt entsprechende Beispiele:The following code shows examples of each:
// Expression-bodied constructor
public ExpressionMembersExample(string label) => this.Label = label;
// Expression-bodied finalizer
~ExpressionMembersExample() => Console.Error.WriteLine("Finalized!");
private string label;
// Expression-bodied get / set accessors.
public string Label
{
get => label;
set => this.label = value ?? "Default label";
}
Hinweis
In diesem Beispiel ist kein Finalizer erforderlich, aber damit soll die Syntax dargestellt werden.This example does not need a finalizer, but it is shown to demonstrate the syntax. Sie sollten in Ihrer Klasse nur einen Finalizer implementieren, wenn es notwendig ist, nicht verwaltete Ressourcen freizugeben.You should not implement a finalizer in your class unless it is necessary to release unmanaged resources. Sie sollten auch die Verwendung der SafeHandle-Klasse in Betracht ziehen, anstatt nicht verwaltete Ressourcen direkt zu verwalten.You should also consider using the SafeHandle class instead of managing unmanaged resources directly.
Diese neuen Speicherorte für Member mit Ausdruckskörper sind ein wichtiger Meilenstein für die Sprache C#: Diese Features wurden von Community-Mitgliedern implementiert, die am Open Source-Projekt Roslyn arbeiten.These new locations for expression-bodied members represent an important milestone for the C# language: These features were implemented by community members working on the open-source Roslyn project.
Das Ändern einer Methode in ein Ausdruckskörpermember ist eine binärkompatible Änderung.Changing a method to an expression bodied member is a binary compatible change.
Throw-AusdrückeThrow expressions
In C# ist throw
schon immer eine Anweisung.In C#, throw
has always been a statement. Da throw
eine Anweisung und kein Ausdruck ist, gab es C#-Konstrukte, in denen diese Anweisung nicht verwendet werden konnte.Because throw
is a statement, not an expression, there were C# constructs where you couldn't use it. Darunter waren bedingte Ausdrücke, NULL-Sammelausdrücke und einige Lambdaausdrücke.These included conditional expressions, null coalescing expressions, and some lambda expressions. Das Hinzufügen von Ausdruckskörpermembern fügt mehr Speicherorte hinzu, bei denen throw
-Ausdrücke nützlich wären.The addition of expression-bodied members adds more locations where throw
expressions would be useful. Damit Sie diese Konstrukte schreiben können, wurden in C# 7.0 Throw-Ausdrücke eingeführt.So that you can write any of these constructs, C# 7.0 introduces throw expressions.
Diese Ergänzung erleichtert das Schreiben ausdrucksbasierteren Codes.This addition makes it easier to write more expression-based code. Sie benötigen zur Fehlerüberprüfung keine weiteren Anweisungen.You don't need additional statements for error checking.
Literale StandardausdrückeDefault literal expressions
Literale Standardausdrücke sind eine Erweiterung von Ausdrücken mit Standardwert.Default literal expressions are an enhancement to default value expressions. Diese Ausdrücke initialisieren eine Variable auf dem Standardwert.These expressions initialize a variable to the default value. Dort, wo Sie vorher das Folgende geschrieben haben:Where you previously would write:
Func<string, bool> whereClause = default(Func<string, bool>);
Können Sie nun den Typ weglassen, der auf der rechten Seite der Initialisierung steht.You can now omit the type on the right-hand side of the initialization:
Func<string, bool> whereClause = default;
Weitere Informationen finden Sie im Abschnitt Standardliteral des Artikels zum default-Operator.For more information, see the default literal section of the default operator article.
Verbesserung der numerischen literalen SyntaxNumeric literal syntax improvements
Falsches Lesen numerischer Konstanten kann Code beim ersten Lesen schwerer verständlich machen.Misreading numeric constants can make it harder to understand code when reading it for the first time. Bitmasken oder andere symbolische Werte können Missverständnisse hervorrufen.Bit masks or other symbolic values are prone to misunderstanding. C# 7.0 enthält zwei neue Funktionen, mit denen Zahlen für den beabsichtigten Zweck so lesbar wie möglich geschrieben werden können: binäre Literale und Zifferntrennzeichen.C# 7.0 includes two new features to write numbers in the most readable fashion for the intended use: binary literals, and digit separators.
Beim Erstellen von Bitmasken oder wenn die binäre Darstellung einer Zahl den Code besonders gut lesbar macht, sollten Sie diese Zahl im Binärformat schreiben:For those times when you're creating bit masks, or whenever a binary representation of a number makes the most readable code, write that number in binary:
public const int Sixteen = 0b0001_0000;
public const int ThirtyTwo = 0b0010_0000;
public const int SixtyFour = 0b0100_0000;
public const int OneHundredTwentyEight = 0b1000_0000;
Das 0b
am Anfang der Konstante gibt an, dass die Zahl als binäre Zahl geschrieben wird.The 0b
at the beginning of the constant indicates that the number is written as a binary number. Binäre Zahlen können lang werden. Daher kann die Einführung von _
als Ziffertrennzeichen wie in der binären Konstante im vorherigen Beispiel gezeigt die Bitmuster übersichtlicher machen.Binary numbers can get long, so it's often easier to see the bit patterns by introducing the _
as a digit separator, as shown in the binary constant in the preceding example. Das Zifferntrennzeichen kann überall in der Konstante angezeigt werden.The digit separator can appear anywhere in the constant. Für Zahlen der Basis 10 wird es üblicherweise als Tausendertrennzeichen verwendet.For base 10 numbers, it is common to use it as a thousands separator. Hexadezimale und binäre numerische Literale dürfen jetzt mit _
beginnen:Hex and binary numeric literals may begin with an _
:
public const long BillionsAndBillions = 100_000_000_000;
Das Zifferntrennzeichen kann auch mit decimal
-, float
- und double
-Typen verwendet werden:The digit separator can be used with decimal
, float
, and double
types as well:
public const double AvogadroConstant = 6.022_140_857_747_474e23;
public const decimal GoldenRatio = 1.618_033_988_749_894_848_204_586_834_365_638_117_720_309_179M;
Insgesamt können Sie numerische Konstanten viel leserlicher deklarieren.Taken together, you can declare numeric constants with much more readability.
out
-Variablenout
variables
Die vorhandene Syntax zur Unterstützung von out
-Parametern wurde in C# 7 verbessert.The existing syntax that supports out
parameters has been improved in C# 7. Nun können Sie out
-Variablen in der Argumentliste eines Methodenaufrufs deklarieren, anstatt eine separate Deklarationsanweisung zu schreiben:You can now declare out
variables in the argument list of a method call, rather than writing a separate declaration statement:
if (int.TryParse(input, out int result))
Console.WriteLine(result);
else
Console.WriteLine("Could not parse input");
Sie sollten den Typ der out
-Variablen aus Gründen der Übersichtlichkeit angeben. Dies wird im vorherigen Beispiel veranschaulicht.You may want to specify the type of the out
variable for clarity, as shown in the preceding example. Die Sprache unterstützt jedoch die Verwendung einer implizit typisierten lokalen Variable:However, the language does support using an implicitly typed local variable:
if (int.TryParse(input, out var answer))
Console.WriteLine(answer);
else
Console.WriteLine("Could not parse input");
- Der Code ist einfacher zu lesen.The code is easier to read.
- Sie deklarieren die out-Variable, wenn Sie sie verwenden, nicht in einer anderen Codezeile weiter oben.You declare the out variable where you use it, not on a preceding line of code.
- Sie müssen keinen Anfangswert zuweisen.No need to assign an initial value.
- Durch das Deklarieren der
out
-Variable, wenn sie in einem Methodenaufruf verwendet wird, können Sie diese nicht versehentlich verwenden, bevor sie zugewiesen wurde.By declaring theout
variable where it's used in a method call, you can't accidentally use it before it is assigned.
- Durch das Deklarieren der
Die in C# 7.0 zum Zulassen von out
-Variablendeklarationen hinzugefügte Syntax wurde erweitert, sodass sie Feldinitialisierer, Eigenschafteninitialisierer, Konstruktorinitialisierer und Abfrageklauseln umfasst.The syntax added in C# 7.0 to allow out
variable declarations has been extended to include field initializers, property initializers, constructor initializers, and query clauses. Sie ermöglicht Code wie im folgenden Beispiel:It enables code such as the following example:
public class B
{
public B(int i, out int j)
{
j = i;
}
}
public class D : B
{
public D(int i) : base(i, out var j)
{
Console.WriteLine($"The value of 'j' is {j}");
}
}
Nicht schließende benannte ArgumenteNon-trailing named arguments
Methodenaufrufe dürfen jetzt benannte Argumente verwenden, die positionellen Argumenten vorstehen, wenn diese benannten Argumente in der richtigen Position verwendet werden.Method calls may now use named arguments that precede positional arguments when those named arguments are in the correct positions. Weitere Informationen finden Sie unter Benannte und optionale Argumente (C#-Programmierhandbuch).For more information, see Named and optional arguments.
Zugriffsmodifizierer private protectedprivate protected access modifier
Ein neuer zusammengesetzter Zugriffsmodifizierer: private protected
zeigt an, dass auf ein Element durch eine es enthaltende Klasse oder durch innerhalb der gleichen Assembly deklarierte abgeleitete Klassen zugegriffen werden darf.A new compound access modifier: private protected
indicates that a member may be accessed by containing class or derived classes that are declared in the same assembly. Während protected internal
den Zugriff durch abgeleitete Klassen oder Klassen, die sich in der gleichen Assembly befinden, erlaubt, schränkt private protected
den Zugriff auf innerhalb der gleichen Assembly deklarierte abgeleitete Typen ein.While protected internal
allows access by derived classes or classes that are in the same assembly, private protected
limits access to derived types declared in the same assembly.
Weitere Informationen finden Sie unter Zugriffsmodifizierer (C#-Referenz) in der Sprachreferenz.For more information, see access modifiers in the language reference.
Verbesserte ÜberladungskandidatenImproved overload candidates
In jedem Release werden die Überladungsauflösungsregeln für Situationen aktualisiert, in denen mehrdeutige Methodenaufrufe eine „naheliegende“ Auswahlmöglichkeit haben.In every release, the overload resolution rules get updated to address situations where ambiguous method invocations have an "obvious" choice. In diesem Release werden drei neue Regeln hinzufügt, damit der Compiler die naheliegende Auswahlmöglichkeit nutzt:This release adds three new rules to help the compiler pick the obvious choice:
- Wenn eine Methodengruppe sowohl Instanz- als auch statische Member enthält, verwirft der Compiler die Instanzmember, wenn die Methode ohne Instanzempfänger oder -kontext aufgerufen wurde.When a method group contains both instance and static members, the compiler discards the instance members if the method was invoked without an instance receiver or context. Der Compiler verwirft die statischen Member, wenn die Methode mit einem Instanzempfänger aufgerufen wurde.The compiler discards the static members if the method was invoked with an instance receiver. Wenn kein Empfänger vorhanden ist, bezieht der Compiler nur statische Member in einen statischen Kontext ein – andernfalls sowohl statische als auch Instanzmember.When there is no receiver, the compiler includes only static members in a static context, otherwise both static and instance members. Wenn unklar ist, ob der Empfänger eine Instanz oder ein Typ ist, bezieht der Compiler beides ein.When the receiver is ambiguously an instance or type, the compiler includes both. Ein statischer Kontext, wo ein impliziter
this
-Instanzempfänger nicht verwendet werden kann, enthält den Text von Membern, wo keinthis
definiert ist, z.B. statische Member, sowie Orte, an denenthis
nicht verwendet werden kann, z.B. Feld- und Konstruktorinitialisierer.A static context, where an implicitthis
instance receiver cannot be used, includes the body of members where nothis
is defined, such as static members, as well as places wherethis
cannot be used, such as field initializers and constructor-initializers. - Wenn eine Methodengruppe einige generische Methoden enthält, deren Typargumente ihre Einschränkungen nicht erfüllen, werden diese Member aus dem Satz von Kandidaten entfernt.When a method group contains some generic methods whose type arguments do not satisfy their constraints, these members are removed from the candidate set.
- Für eine Methodengruppenkonvertierung werden Kandidatenmethoden, deren Rückgabetyp nicht mit dem des Delegaten übereinstimmt, aus dem Satz entfernt.For a method group conversion, candidate methods whose return type doesn't match up with the delegate's return type are removed from the set.
Sie werden diese Änderung bemerken, da Sie weniger Compilerfehler für mehrdeutige Methodenüberladungen finden werden, wenn Sie sicher sind, welche Methode besser ist.You'll only notice this change because you'll find fewer compiler errors for ambiguous method overloads when you are sure which method is better.
Ermöglichen von effizienterem sicherem CodeEnabling more efficient safe code
Sie sollten C#-Code sicher schreiben können, der so leistungsstark ist wie unsicherer Code.You should be able to write C# code safely that performs as well as unsafe code. Sicherer Code vermeidet Fehlerklassen, z.B. Pufferüberläufe, verirrte Zeiger und andere Fehler beim Arbeitsspeicherzugriff.Safe code avoids classes of errors, such as buffer overruns, stray pointers, and other memory access errors. Diese neuen Features erweitern die Funktionen des überprüfbaren sicheren Codes.These new features expand the capabilities of verifiable safe code. Schreiben Sie mithilfe sicherer Konstrukte mehr Code.Strive to write more of your code using safe constructs. Diese Features erleichtern dies.These features make that easier.
Die folgenden neuen Features unterstützen das Design der besseren Leistung für sicheren Code:The following new features support the theme of better performance for safe code:
- Sie können ohne Anheften auf feste Felder zugreifen.You can access fixed fields without pinning.
- Sie können
ref
erneut lokale Variablen zuweisen.You can reassignref
local variables. - Sie können Initialisierer auf
stackalloc
-Arrays verwenden.You can use initializers onstackalloc
arrays. - Sie können
fixed
-Anweisungen mit jedem Typ verwenden, der ein Muster unterstützt.You can usefixed
statements with any type that supports a pattern. - Sie können zusätzliche generische Einschränkungen verwenden.You can use additional generic constraints.
- Den
in
-Modifizierer für Parameter zur Angabe, dass ein Argument durch Verweis übergeben, von der aufgerufenen Methode aber nicht verändert wird.Thein
modifier on parameters, to specify that an argument is passed by reference but not modified by the called method. Das Hinzufügen des Modifizierersin
zu einem Argument ist eine quellkompatible Änderung.Adding thein
modifier to an argument is a source compatible change. - Der
ref readonly
-Modifizierer für die Methodenrückgabe, um anzugeben, dass eine Methode ihren Wert als Verweis zurückgibt und keinen Schreibzugriff auf dieses Objekt zulässt.Theref readonly
modifier on method returns, to indicate that a method returns its value by reference but doesn't allow writes to that object. Das Hinzufügen des Modifizierersref readonly
ist eine quellkompatible Änderung, wenn die Rückgabe einem Wert zugewiesen wird.Adding theref readonly
modifier is a source compatible change, if the return is assigned to a value. Das Hinzufügen des Modifizierersreadonly
zu einer vorhandenenref
-Rückgabeanweisung ist eine inkompatible Änderung.Adding thereadonly
modifier to an existingref
return statement is an incompatible change. Es verlangt von Aufrufern das Aktualisieren der lokalenref
-Variablen, um denreadonly
-Modifizierer einzuschließen.It requires callers to update the declaration ofref
local variables to include thereadonly
modifier. - Die
readonly struct
-Deklaration, um anzugeben, dass eine Struktur unveränderlich ist und ihren Membermethoden alsin
-Parameter übergeben werden sollte.Thereadonly struct
declaration, to indicate that a struct is immutable and should be passed as anin
parameter to its member methods. Das Hinzufügen des Modifizierersreadonly
zu einer vorhandenen Strukturdeklaration ist eine binärkompatible Änderung.Adding thereadonly
modifier to an existing struct declaration is a binary compatible change. - Die
ref struct
-Deklaration, um anzugeben, dass ein Strukturtyp direkt auf verwalteten Arbeitsspeicher zugreift und immer per Stapel zugeordnet werden muss.Theref struct
declaration, to indicate that a struct type accesses managed memory directly and must always be stack allocated. Das Hinzufügen des Modifizierersref
zu einer vorhandenenstruct
-Deklaration ist eine inkompatible Änderung.Adding theref
modifier to an existingstruct
declaration is an incompatible change. Einref struct
kann kein Mitglied einer Klasse sein oder an anderen Stellen verwendet werden, wo es auf dem Heap zugewiesen werden könnte.Aref struct
cannot be a member of a class or used in other locations where it may be allocated on the heap.
Weitere Informationen zu all diesen Änderungen finden Sie unter Schreiben von sicherem und effizientem Code.You can read more about all these changes in Write safe efficient code.
Lokale ref-Variablen und RückgabetypenRef locals and returns
Diese Funktion ermöglicht Algorithmen, die Verweise auf Variablen verwenden und zurückgeben, die an anderer Stelle definiert sind.This feature enables algorithms that use and return references to variables defined elsewhere. Ein Beispiel ist das Arbeiten mit großen Matrizen und die Suche nach einem einzigen Ort mit bestimmten Eigenschaften.One example is working with large matrices, and finding a single location with certain characteristics. Die folgende Methode gibt einen Verweis auf diesen Speicher in der Matrix zurück:The following method returns a reference to that storage in the matrix:
public static ref int Find(int[,] matrix, Func<int, bool> predicate)
{
for (int i = 0; i < matrix.GetLength(0); i++)
for (int j = 0; j < matrix.GetLength(1); j++)
if (predicate(matrix[i, j]))
return ref matrix[i, j];
throw new InvalidOperationException("Not found");
}
Sie können den Rückgabewert als ref
deklarieren und diesen Wert wie im folgenden Code gezeigt in der Matrix ändern:You can declare the return value as a ref
and modify that value in the matrix, as shown in the following code:
ref var item = ref MatrixSearch.Find(matrix, (val) => val == 42);
Console.WriteLine(item);
item = 24;
Console.WriteLine(matrix[4, 2]);
Die C#-Sprache verfügt über mehrere Regeln, die Sie vor einer falschen Verwendung der lokalen ref
-Variablen und Rückgabetypen schützen:The C# language has several rules that protect you from misusing the ref
locals and returns:
- Sie müssen der Methodensignatur und allen
return
-Anweisungen einer Methode dasref
-Schlüsselwort hinzufügen.You must add theref
keyword to the method signature and to allreturn
statements in a method.- Dadurch wird deutlich, dass Rückgaben in der gesamten Methode als Verweis erfolgen.That makes it clear the method returns by reference throughout the method.
- Eine
ref return
-Rückgabe kann einer Wert- oder einerref
-Variablen zugewiesen werden.Aref return
may be assigned to a value variable, or aref
variable.- Der Aufrufer steuert, ob der Rückgabewert kopiert werden soll.The caller controls whether the return value is copied or not. Durch Auslassen des
ref
-Modifizierers beim Zuweisen des Rückgabewerts gibt der Aufrufer an, dass der Wert kopiert werden und nicht etwa ein Verweis auf den Speicher erfolgen soll.Omitting theref
modifier when assigning the return value indicates that the caller wants a copy of the value, not a reference to the storage.
- Der Aufrufer steuert, ob der Rückgabewert kopiert werden soll.The caller controls whether the return value is copied or not. Durch Auslassen des
- Sie können einer lokalen
ref
-Variablen keinen Rückgabewert einer Standardmethode zuweisen.You can't assign a standard method return value to aref
local variable.- Dadurch werden Aussagen wie
ref int i = sequence.Count();
nicht zugelassen.That disallows statements likeref int i = sequence.Count();
- Dadurch werden Aussagen wie
- Sie können
ref
nicht an eine Variable zurückgeben, deren Lebensdauer nicht über die Ausführung der Methode hinausgeht.You can't return aref
to a variable whose lifetime doesn't extend beyond the execution of the method.- Das bedeutet, dass Sie keinen Verweis auf eine lokale Variable oder eine Variable mit einem ähnlichen Bereich zurückgeben können.That means you can't return a reference to a local variable or a variable with a similar scope.
- Lokale
ref
-Variablen und Rückgabewerte können nicht in Verbindung mit asynchronen Methoden verwendet werden.ref
locals and returns can't be used with async methods.- Der Compiler kann nicht feststellen, ob die Variable, auf die verwiesen wird, bei der Rückgabe der asynchronen Methode auf ihren endgültigen Wert festgelegt ist.The compiler can't know if the referenced variable has been set to its final value when the async method returns.
Das Hinzufügen von lokalen ref-Variablen und ref-Rückgaben ermöglicht effizientere Algorithmen, da Werte nicht kopiert oder dereferenzierende Vorgänge nicht mehrmals ausgeführt werden.The addition of ref locals and ref returns enables algorithms that are more efficient by avoiding copying values, or performing dereferencing operations multiple times.
Das Hinzufügen von ref
zum Rückgabewert stellt eine quellkompatible Änderung dar.Adding ref
to the return value is a source compatible change. Vorhandener Code lässt sich kompilieren, der ref-Rückgabewert wird aber bei der Zuweisung kopiert.Existing code compiles, but the ref return value is copied when assigned. Aufrufer müssen den Speicher für den Rückgabewert in eine lokale ref
-Variable aktualisieren, um die Rückgabe als Verweis zu speichern.Callers must update the storage for the return value to a ref
local variable to store the return as a reference.
Lokale ref
-Variablen werden jetzt möglicherweise neu zugewiesen, um nach der Initialisierung auf verschiedene Instanzen zu verweisen.Now, ref
locals may be reassigned to refer to different instances after being initialized. Der folgende Code wird jetzt kompiliert:The following code now compiles:
ref VeryLargeStruct refLocal = ref veryLargeStruct; // initialization
refLocal = ref anotherVeryLargeStruct; // reassigned, refLocal refers to different storage.
Weitere Informationen finden Sie im Artikel zu ref
-Rückgaben und lokalen ref
-Variablen und im Artikel zu foreach
.For more information, see the article on ref
returns and ref
locals, and the article on foreach
.
Weitere Informationen finden Sie im Artikel Schlüsselwort „ref“.For more information, see the ref keyword article.
Bedingte ref
AusdrückeConditional ref
expressions
Schließlich kann ein bedingter Ausdruck als Ergebnis einen Verweis anstatt eines Werts erzeugen.Finally, the conditional expression may produce a ref result instead of a value result. Beispielsweise würden Sie folgendes schreiben, um einen Verweis auf das erste Element in einem von zwei Arrays abzurufen:For example, you would write the following to retrieve a reference to the first element in one of two arrays:
ref var r = ref (arr != null ? ref arr[0] : ref otherArr[0]);
Die Variable r
ist ein Verweis auf den ersten Wert in arr
oder otherArr
.The variable r
is a reference to the first value in either arr
or otherArr
.
Weitere Informationen finden Sie unter conditional-Operator (?:) in der Sprachreferenz.For more information, see conditional operator (?:) in the language reference.
Modifizierer für in
-Parameterin
parameter modifier
Das in
-Schlüsselwort ergänzt die vorhandenen Schlüsselwörter ref und out zum Übergeben von Argumenten als Verweis.The in
keyword complements the existing ref and out keywords to pass arguments by reference. Durch das in
-Schlüsselwort wird festgelegt, dass das Argument als Verweis übergeben wird, die aufgerufene Methode aber nicht den Wert ändert.The in
keyword specifies passing the argument by reference, but the called method doesn't modify the value.
Sie können Überladungen, die nach Wert oder nach schreibgeschütztem Verweis übergeben werden, wie im folgenden Code gezeigt deklarieren:You may declare overloads that pass by value or by readonly reference, as shown in the following code:
static void M(S arg);
static void M(in S arg);
Die Überladung, die nach Wert übergeben wird (die erste im obigen Beispiel) ist besser als die Version, die nach schreibgeschütztem Verweis übergeben wird.The by value (first in the preceding example) overload is better than the by readonly reference version. Um die Version mit dem readonly-Verweisargument aufzurufen, müssen Sie auch den in
-Modifizierer beim Aufrufen der Methode einbeziehen.To call the version with the readonly reference argument, you must include the in
modifier when calling the method.
Weitere Informationen finden Sie im Artikel zum in
-Parametermodifizierer.For more information, see the article on the in
parameter modifier.
Weitere Typen unterstützen die fixed
-AnweisungMore types support the fixed
statement
Die fixed
-Anweisung unterstützte eine begrenzte Anzahl von Typen.The fixed
statement supported a limited set of types. Ab C# 7.3 kann jeder Typ, der eine GetPinnableReference()
-Methode enthält, die eine ref T
oder ref readonly T
zurückgibt, fixed
sein.Starting with C# 7.3, any type that contains a GetPinnableReference()
method that returns a ref T
or ref readonly T
may be fixed
. Dieses Feature hinzuzufügen, bedeutet, dass fixed
mit System.Span<T> und verwandten Typen genutzt werden kann.Adding this feature means that fixed
can be used with System.Span<T> and related types.
Weitere Informationen finden Sie im Artikel zur fixed
-Anweisung in der Sprachreferenz.For more information, see the fixed
statement article in the language reference.
Indizieren von fixed
-Feldern erfordert kein AnheftenIndexing fixed
fields does not require pinning
Betrachten Sie diese Struktur:Consider this struct:
unsafe struct S
{
public fixed int myFixedField[10];
}
In früheren Versionen von C# mussten Sie eine Variable für den Zugriff auf eine der ganzen Zahlen anheften, die Teil von myFixedField
sind.In earlier versions of C#, you needed to pin a variable to access one of the integers that are part of myFixedField
. Der folgende Code wird kompiliert, ohne die Variable p
in einer separaten fixed
-Anweisung anzuheften:Now, the following code compiles without pinning the variable p
inside a separate fixed
statement:
class C
{
static S s = new S();
unsafe public void M()
{
int p = s.myFixedField[5];
}
}
Die Variable p
greift auf ein Element in myFixedField
zu.The variable p
accesses one element in myFixedField
. Sie müssen keine separate int*
-Variable deklarieren.You don't need to declare a separate int*
variable. Sie benötigen weiterhin einen unsafe
-Kontext.You still need an unsafe
context. In früheren Versionen von C# müssen Sie einen zweiten festen Zeiger deklarieren:In earlier versions of C#, you need to declare a second fixed pointer:
class C
{
static S s = new S();
unsafe public void M()
{
fixed (int* ptr = s.myFixedField)
{
int p = ptr[5];
}
}
}
Weitere Informationen finden Sie im Artikel zur fixed
-Anweisung.For more information, see the article on the fixed
statement.
stackalloc
-Arrays unterstützen Initialisiererstackalloc
arrays support initializers
Sie konnten schon die Werte für Elemente in einem Array angeben, wenn Sie es initialisierten:You've been able to specify the values for elements in an array when you initialize it:
var arr = new int[3] {1, 2, 3};
var arr2 = new int[] {1, 2, 3};
Nun kann die gleiche Syntax auf Arrays angewendet werden, die mit stackalloc
deklariert werden:Now, that same syntax can be applied to arrays that are declared with stackalloc
:
int* pArr = stackalloc int[3] {1, 2, 3};
int* pArr2 = stackalloc int[] {1, 2, 3};
Span<int> arr = stackalloc [] {1, 2, 3};
Weitere Informationen finden Sie im Artikel zum stackalloc
-Operator.For more information, see the stackalloc
operator article.
Verbesserte generische EinschränkungenEnhanced generic constraints
Sie können jetzt Typ System.Enum oder System.Delegate als Basisklasseneinschränkungen für einen Typparameter angeben.You can now specify the type System.Enum or System.Delegate as base class constraints for a type parameter.
Sie können auch die neue unmanaged
-Einschränkung nutzen, um anzugeben, dass der Typparameter ein nicht verwalteter Non-Nullable-Typ sein muss.You can also use the new unmanaged
constraint, to specify that a type parameter must be a non-nullable unmanaged type.
Weitere Informationen finden Sie in den Artikeln zu generischen where
-Einschränkungen und Einschränkungen für Typparameter.For more information, see the articles on where
generic constraints and constraints on type parameters.
Das Hinzufügen dieser Einschränkungen zu vorhandenen Typen ist eine inkompatible Änderung.Adding these constraints to existing types is an incompatible change. Geschlossene generische Typen erfüllen diese neuen Einschränkungen möglicherweise nicht mehr.Closed generic types may no longer meet these new constraints.
Generalisierte asynchrone RückgabetypenGeneralized async return types
Das Zurückgeben eines Task
-Objekts von asynchronen Methoden kann Leistungsengpässe in bestimmten Pfaden verursachen.Returning a Task
object from async methods can introduce performance bottlenecks in certain paths. Task
ist ein Verweistyp, seine Verwendung bedeutet also das Zuordnen eines Objekts.Task
is a reference type, so using it means allocating an object. In Fällen, in denen eine mit dem async
-Modifizierer deklarierte Methode ein zwischengespeichertes Ergebnis zurückgibt oder synchron abschließt, können die zusätzlichen Zuordnungen viel Zeit bei der Ausführung kritischer Codeabschnitte kosten.In cases where a method declared with the async
modifier returns a cached result, or completes synchronously, the extra allocations can become a significant time cost in performance critical sections of code. Es kann kostspielig werden, wenn diese Zuordnungen in engen Schleifen auftreten.It can become costly if those allocations occur in tight loops.
Durch die neue Sprachfunktion sind die Rückgabetypen asynchroner Methoden nicht auf Task
, Task<T>
und void
beschränkt.The new language feature means that async method return types aren't limited to Task
, Task<T>
, and void
. Der zurückgegebene Typ muss noch immer das asynchrone Muster erfüllen, d.h. dass eine GetAwaiter
-Methode verfügbar sein muss.The returned type must still satisfy the async pattern, meaning a GetAwaiter
method must be accessible. Als konkretes Beispiel wurde der ValueTask
-Typ zu .NET hinzugefügt, um diese neue Sprachfunktion zu nutzen:As one concrete example, the ValueTask
type has been added to .NET to make use of this new language feature:
public async ValueTask<int> Func()
{
await Task.Delay(100);
return 5;
}
Hinweis
Sie müssen das NuGet-Paket System.Threading.Tasks.Extensions
hinzufügen, um den Typ ValueTask<TResult> verwenden zu können.You need to add the NuGet package System.Threading.Tasks.Extensions
> in order to use the ValueTask<TResult> type.
Diese Verbesserung ist besonders für Bibliotheksautoren hilfreich, um die Zuordnung von Task
in leistungskritischem Code zu verhindern.This enhancement is most useful for library authors to avoid allocating a Task
in performance critical code.
Neue CompileroptionenNew compiler options
Neue Compileroptionen unterstützen neue Build- und DevOpsszenarien für C#-Programme.New compiler options support new build and DevOps scenarios for C# programs.
Generierung der ReferenzassemblyReference assembly generation
Es gibt zwei neue Compileroptionen, die reine Verweisassemblys generieren: ProduceReferenceAssembly und ProduceOnlyReferenceAssembly.There are two new compiler options that generate reference-only assemblies: ProduceReferenceAssembly and ProduceOnlyReferenceAssembly. In den verlinkten Artikeln werden diese Optionen und Referenzassemblys ausführlich beschrieben.The linked articles explain these options and reference assemblies in more detail.
Öffentliche oder Open Source-SignierungPublic or Open Source signing
Die Compileroption PublicSign weist den Compiler an, die Assembly mit einem öffentlichen Schlüssel zu signieren.The PublicSign compiler option instructs the compiler to sign the assembly using a public key. Die Assembly wird als signiert markiert, aber die Signatur wird dem öffentlichen Schlüssel entnommen.The assembly is marked as signed, but the signature is taken from the public key. Mit dieser Option können Sie signierte Assemblys aus Open Source-Projekten mit einem öffentlichen Schlüssel erstellen.This option enables you to build signed assemblies from open-source projects using a public key.
Weitere Informationen finden Sie im Artikel zur PublicSign-Compileroption.For more information, see the PublicSign compiler option article.
pathmappathmap
Die Compileroption PathMap weist den Compiler an, Quellpfade aus der Buildumgebung mit zugeordneten Quellpfaden zu ersetzen.The PathMap compiler option instructs the compiler to replace source paths from the build environment with mapped source paths. Die Option PathMapCallerFilePathAttribute steuert den Quellpfad, der vom Compiler in PDB-Dateien oder für geschrieben wird.The PathMap option controls the source path written by the compiler to PDB files or for the CallerFilePathAttribute.
Weitere Informationen finden Sie im Artikel zur PathMap-Compileroption.For more information, see the PathMap compiler option article.