Operatoren en expressies voor lidtoegang: de operatoren punt, indexeerfunctie en aanroep.
U gebruikt verschillende operators en expressies om toegang te krijgen tot een typelid. Deze operators omvatten toegang tot leden (.
), matrixelement- of indexeerfunctietoegang ([]
), index-from-end (^
), bereik (..
), null-voorwaardelijke operatoren (?.
en ?[]
) en methode-aanroep (()
). Dit zijn onder andere de operatoren voor toegang tot null-voorwaardelijke leden (?.
) en indexeerfunctietoegang (?[]
).
.
(lidtoegang): toegang krijgen tot een lid van een naamruimte of een type[]
(toegang tot matrixelement of indexeerfunctie): voor toegang tot een matrixelement of een typeindexeerfunctie?.
en?[]
(null-voorwaardelijke operators): als u alleen een bewerking voor lid- of elementtoegang wilt uitvoeren als een operand niet null is()
(aanroep): een geopende methode aanroepen of een gemachtigde aanroepen^
(index van einde): om aan te geven dat de elementpositie zich van het einde van een reeks bevindt..
(bereik): om een reeks indexen op te geven die u kunt gebruiken om een reeks reekselementen te verkrijgen
Expressie voor lidtoegang .
U gebruikt het .
token om toegang te krijgen tot een lid van een naamruimte of een type, zoals in de volgende voorbeelden wordt gedemonstreert:
- Gebruik
.
dit diagram om toegang te krijgen tot een geneste naamruimte binnen een naamruimte, zoals in het volgende voorbeeld van eenusing
instructie wordt weergegeven:
using System.Collections.Generic;
- Gebruik
.
dit diagram om een gekwalificeerde naam te vormen voor toegang tot een type binnen een naamruimte, zoals in de volgende code wordt weergegeven:
System.Collections.Generic.IEnumerable<int> numbers = [1, 2, 3];
Gebruik een using
richtlijn om het gebruik van gekwalificeerde namen optioneel te maken.
- Gebruik
.
dit diagram om toegang te krijgen tot leden van het type, statisch en niet-statisch, zoals in de volgende code wordt weergegeven:
List<double> constants =
[
Math.PI,
Math.E
];
Console.WriteLine($"{constants.Count} values to show:");
Console.WriteLine(string.Join(", ", constants));
// Output:
// 2 values to show:
// 3.14159265358979, 2.71828182845905
U kunt ook toegang krijgen .
tot een extensiemethode.
Operator voor indexeerfunctie []
Vierkante haken, []
worden meestal gebruikt voor toegang tot matrices, indexeerfuncties of aanwijzerelementen. Vanaf C# 12 []
plaatst u een verzamelingsexpressie.
Toegang tot matrices
In het volgende voorbeeld ziet u hoe u toegang hebt tot matrixelementen:
int[] fib = new int[10];
fib[0] = fib[1] = 1;
for (int i = 2; i < fib.Length; i++)
{
fib[i] = fib[i - 1] + fib[i - 2];
}
Console.WriteLine(fib[fib.Length - 1]); // output: 55
double[,] matrix = new double[2,2];
matrix[0,0] = 1.0;
matrix[0,1] = 2.0;
matrix[1,0] = matrix[1,1] = 3.0;
var determinant = matrix[0,0] * matrix[1,1] - matrix[1,0] * matrix[0,1];
Console.WriteLine(determinant); // output: -3
Als een matrixindex buiten de grenzen van de corresponderende dimensie van een matrix valt, wordt er een IndexOutOfRangeException gegenereerd.
Zoals in het voorgaande voorbeeld wordt weergegeven, gebruikt u ook vierkante haken wanneer u een matrixtype declareert of een matrixexemplaren instantiëren.
Zie Matrices voor meer informatie over matrices.
Toegang tot indexeerfunctie
In het volgende voorbeeld wordt het .NET-type Dictionary<TKey,TValue> gebruikt om de toegang tot de indexeerfunctie te demonstreren:
var dict = new Dictionary<string, double>();
dict["one"] = 1;
dict["pi"] = Math.PI;
Console.WriteLine(dict["one"] + dict["pi"]); // output: 4.14159265358979
Met indexeerfuncties kunt u exemplaren van een door de gebruiker gedefinieerd type op dezelfde manier indexeren als matrixindexering. In tegenstelling tot matrixindexen, die geheel getal moeten zijn, kunnen de indexeerparameters van elk type worden gedeclareerd.
Zie Indexeerfuncties voor meer informatie over indexeerfuncties.
Andere gebruiksgegevens van []
Zie de sectie Pointer-elementtoegangsoperator [] van het artikel Met aanwijzer gerelateerde operators voor informatie over toegang tot aanwijzers . Zie het artikel verzamelingsexpressies voor informatie over verzamelingsexpressies .
U gebruikt ook vierkante haken om kenmerken op te geven:
[System.Diagnostics.Conditional("DEBUG")]
void TraceMethod() {}
Null-voorwaardelijke operators ?.
en ?[]
Een operator met null-voorwaardelijke voorwaarden past een bewerking voor lidtoegang () of elementtoegang (?.
?[]
) alleen toe op de operand als die operand niet-null evalueert; anders wordt deze geretourneerdnull
. Met andere woorden:
Als
a
dit wordt geëvalueerdnull
, is het resultaat vana?.x
ofa?[x]
isnull
het .Als
a
dit resulteert in een niet-null-waarde, is het resultaat vana?.x
ofa?[x]
hetzelfde als respectievelijk het resultaat vana.x
ofa[x]
, respectievelijk.Notitie
Als
a.x
ofa[x]
een uitzondering genereert ofa?.x
a?[x]
dezelfde uitzondering genereert voor niet-nulla
. Alsa
het bijvoorbeeld een niet-null-matrixexemplaren is enx
zich buiten de grenzen vana
bevindt,a?[x]
wordt er een IndexOutOfRangeException.
De null-voorwaardelijke operators zijn kortsluiting. Als één bewerking in een keten van voorwaardelijke lid- of elementtoegangsbewerkingen retourneert null
, wordt de rest van de keten niet uitgevoerd. In het volgende voorbeeld B
wordt dit niet geëvalueerd als A
dit wordt null
geëvalueerd en C
niet wordt geëvalueerd als A
of B
wordt geëvalueerd:null
A?.B?.Do(C);
A?.B?[C];
Als A
het mogelijk null is, maar B
niet C
null zou zijn als A niet null is, hoeft u alleen de operator null-voorwaardelijk toe te passen op A
:
A?.B.C();
In het voorgaande voorbeeld B
wordt deze niet geëvalueerd en C()
wordt deze niet aangeroepen als A
null is. Als de toegang tot gekoppelde leden echter wordt onderbroken, bijvoorbeeld door haakjes zoals in (A?.B).C()
, gebeurt kortsluiting niet.
In de volgende voorbeelden ziet u het gebruik van de ?.
en ?[]
operators:
double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
{
return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
}
var sum1 = SumNumbers(null, 0);
Console.WriteLine(sum1); // output: NaN
List<double[]?> numberSets =
[
[1.0, 2.0, 3.0],
null
];
var sum2 = SumNumbers(numberSets, 0);
Console.WriteLine(sum2); // output: 6
var sum3 = SumNumbers(numberSets, 1);
Console.WriteLine(sum3); // output: NaN
namespace MemberAccessOperators2;
public static class NullConditionalShortCircuiting
{
public static void Main()
{
Person? person = null;
person?.Name.Write(); // no output: Write() is not called due to short-circuit.
try
{
(person?.Name).Write();
}
catch (NullReferenceException)
{
Console.WriteLine("NullReferenceException");
}; // output: NullReferenceException
}
}
public class Person
{
public required FullName Name { get; set; }
}
public class FullName
{
public required string FirstName { get; set; }
public required string LastName { get; set; }
public void Write() => Console.WriteLine($"{FirstName} {LastName}");
}
De eerste van de voorgaande twee voorbeelden maakt ook gebruik van de operator ??
null-coalescing om een alternatieve expressie op te geven voor het geval het resultaat van een null-voorwaardelijke bewerking is null
.
Als a.x
of a[x]
van een niet-null-waardetype T
is, a?.x
of a?[x]
van het overeenkomstige null-waardetype T?
is. Als u een expressie van het type T
nodig hebt, past u de operator ??
null-coalescing toe op een null-voorwaardelijke expressie, zoals in het volgende voorbeeld wordt weergegeven:
int GetSumOfFirstTwoOrDefault(int[]? numbers)
{
if ((numbers?.Length ?? 0) < 2)
{
return 0;
}
return numbers[0] + numbers[1];
}
Console.WriteLine(GetSumOfFirstTwoOrDefault(null)); // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault([])); // output: 0
Console.WriteLine(GetSumOfFirstTwoOrDefault([3, 4, 5])); // output: 7
Als u in het voorgaande voorbeeld de ??
operator niet gebruikt, numbers?.Length < 2
wordt geëvalueerd false
wanneer numbers
dat het geval is null
.
Notitie
De ?.
operator evalueert de linkeroperand niet meer dan één keer, wat garandeert dat deze niet kan worden gewijzigd null
nadat deze is geverifieerd als niet-null.
De operator ?.
voor toegang tot null-voorwaardelijke leden wordt ook wel de Operator Elvis genoemd.
Thread-veilige gemachtigde aanroepen
Gebruik de ?.
operator om te controleren of een gemachtigde niet-null is en deze op een threadveilige manier aanroept (bijvoorbeeld wanneer u een gebeurtenis genereert), zoals in de volgende code wordt weergegeven:
PropertyChanged?.Invoke(…)
Deze code is gelijk aan de volgende code:
var handler = this.PropertyChanged;
if (handler != null)
{
handler(…);
}
Het voorgaande voorbeeld is een thread-veilige manier om ervoor te zorgen dat alleen een niet-null-waarde handler
wordt aangeroepen. Omdat gedelegeerde exemplaren onveranderbaar zijn, kan er geen thread het object wijzigen waarnaar wordt verwezen door de handler
lokale variabele. Met name als de code die door een andere thread wordt uitgevoerd, zich afmeldt voor de PropertyChanged
gebeurtenis en PropertyChanged
null
voordat handler
deze wordt aangeroepen, blijft het object waarnaar wordt verwezen handler
, ongewijzigd.
Aanroepexpressie ()
Gebruik haakjes, ()
om een methode aan te roepen of een gemachtigde aan te roepen.
In het volgende voorbeeld ziet u hoe u een methode aanroept met of zonder argumenten en hoe u een gemachtigde aanroept:
Action<int> display = s => Console.WriteLine(s);
List<int> numbers =
[
10,
17
];
display(numbers.Count); // output: 2
numbers.Clear();
display(numbers.Count); // output: 0
U gebruikt ook haakjes wanneer u een constructor aanroept met de new
operator.
Andere gebruiksrechten van ()
U gebruikt ook haakjes om de volgorde aan te passen waarin bewerkingen in een expressie moeten worden geëvalueerd. Zie C#-operators voor meer informatie.
Cast-expressies, die expliciete typeconversies uitvoeren, gebruiken ook haakjes.
Index van eindoperator ^
Index- en bereikoperators kunnen worden gebruikt met een type dat kan worden geteld. Een type dat kan worden geteld, is een type met een int
eigenschap met de Length
naam of Count
met een toegankelijke get
accessor. Verzamelingsexpressies zijn ook afhankelijk van telbare typen.
De ^
operator geeft de positie van het element aan vanaf het einde van een reeks. Voor een reeks lengte length
wijst ^n
u naar het element met verschuiving length - n
vanaf het begin van een reeks. Verwijst bijvoorbeeld ^1
naar het laatste element van een reeks en ^length
verwijst naar het eerste element van een reeks.
int[] xs = [0, 10, 20, 30, 40];
int last = xs[^1];
Console.WriteLine(last); // output: 40
List<string> lines = ["one", "two", "three", "four"];
string prelast = lines[^2];
Console.WriteLine(prelast); // output: three
string word = "Twenty";
Index toFirst = ^word.Length;
char first = word[toFirst];
Console.WriteLine(first); // output: T
Zoals in het voorgaande voorbeeld wordt weergegeven, is de expressie ^e
van het System.Index type. In expressie ^e
moet het resultaat e
impliciet converteerbaar zijn naar int
.
U kunt de ^
operator ook gebruiken met de bereikoperator om een bereik van indexen te maken. Zie Indexen en bereiken voor meer informatie.
Vanaf C# 13 kan de index van de eindoperator worden gebruikt in een object-initialisatiefunctie.
Bereikoperator ..
De ..
operator geeft het begin en einde van een reeks indexen aan als operanden. De linkeroperand is een inclusief begin van een bereik. De rechteroperand is een exclusief einde van een bereik. Een van de operanden kan een index zijn vanaf het begin of vanaf het einde van een reeks, zoals in het volgende voorbeeld wordt weergegeven:
int[] numbers = [0, 10, 20, 30, 40, 50];
int start = 1;
int amountToTake = 3;
int[] subset = numbers[start..(start + amountToTake)];
Display(subset); // output: 10 20 30
int margin = 1;
int[] inner = numbers[margin..^margin];
Display(inner); // output: 10 20 30 40
string line = "one two three";
int amountToTakeFromEnd = 5;
Range endIndices = ^amountToTakeFromEnd..^0;
string end = line[endIndices];
Console.WriteLine(end); // output: three
void Display<T>(IEnumerable<T> xs) => Console.WriteLine(string.Join(" ", xs));
Zoals in het voorgaande voorbeeld wordt weergegeven, is de expressie a..b
van het System.Range type. In expressie a..b
moeten de resultaten van a
en b
impliciet worden omgezet in Int32 of Index.
Belangrijk
Impliciete conversies van int
waaruit Index
een ArgumentOutOfRangeException waarde wordt gegenereerd wanneer de waarde negatief is.
U kunt alle operanden van de ..
operator weglaten om een open-eindbereik te verkrijgen:
a..
is gelijk aana..^0
..b
is gelijk aan0..b
..
is gelijk aan0..^0
int[] numbers = [0, 10, 20, 30, 40, 50];
int amountToDrop = numbers.Length / 2;
int[] rightHalf = numbers[amountToDrop..];
Display(rightHalf); // output: 30 40 50
int[] leftHalf = numbers[..^amountToDrop];
Display(leftHalf); // output: 0 10 20
int[] all = numbers[..];
Display(all); // output: 0 10 20 30 40 50
void Display<T>(IEnumerable<T> xs) => Console.WriteLine(string.Join(" ", xs));
In de volgende tabel ziet u verschillende manieren om verzamelingsbereiken uit te drukken:
Operatorexpressie voor bereik | Beschrijving |
---|---|
.. |
Alle waarden in de verzameling. |
..end |
Waarden van begin tot end exclusief. |
start.. |
Waarden van inclusief start tot het einde. |
start..end |
Waarden van inclusief start tot end exclusief. |
^start.. |
Waarden van inclusief start tot het einde tellen vanaf het einde. |
..^end |
Waarden van het begin tot het end exclusief tellen vanaf het einde. |
start..^end |
Waarden van start inclusief tot end exclusief tellen vanaf het einde. |
^start..^end |
Waarden van start inclusief tot end uitsluitend beide tellen vanaf het einde. |
In het volgende voorbeeld ziet u het effect van het gebruik van alle bereiken die in de voorgaande tabel worden weergegeven:
int[] oneThroughTen =
[
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
];
Write(oneThroughTen, ..);
Write(oneThroughTen, ..3);
Write(oneThroughTen, 2..);
Write(oneThroughTen, 3..5);
Write(oneThroughTen, ^2..);
Write(oneThroughTen, ..^3);
Write(oneThroughTen, 3..^4);
Write(oneThroughTen, ^4..^2);
static void Write(int[] values, Range range) =>
Console.WriteLine($"{range}:\t{string.Join(", ", values[range])}");
// Sample output:
// 0..^0: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
// 0..3: 1, 2, 3
// 2..^0: 3, 4, 5, 6, 7, 8, 9, 10
// 3..5: 4, 5
// ^2..^0: 9, 10
// 0..^3: 1, 2, 3, 4, 5, 6, 7
// 3..^4: 4, 5, 6
// ^4..^2: 7, 8
Zie Indexen en bereiken voor meer informatie.
Het ..
token wordt ook gebruikt voor het verspreide element in een verzamelingsexpressie.
Overbelasting van operatoren
De .
operators , ^
()
en ..
operators kunnen niet worden overbelast. De []
operator wordt ook beschouwd als een niet-overbelastingsbare operator. Gebruik indexeerfuncties ter ondersteuning van indexering met door de gebruiker gedefinieerde typen.
C#-taalspecificatie
Zie de volgende secties van de C#-taalspecificatie voor meer informatie:
Zie de notitie van het functievoorstel voor meer informatie over indexen en bereiken.