Share via


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 (?[]).

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 een using 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.

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 .

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. Dat betekent:

  • Als a dit wordt geëvalueerd null, is het resultaat van a?.x of a?[x] is nullhet .

  • Als a dit resulteert in een niet-null-waarde, is het resultaat van a?.x of a?[x] hetzelfde als respectievelijk het resultaat van a.x of a[x], respectievelijk.

    Notitie

    Als a.x of a[x] een uitzondering genereert of a?.x a?[x] dezelfde uitzondering genereert voor niet-null a. Als a het bijvoorbeeld een niet-null-matrixexemplaren is en x zich buiten de grenzen van abevindt, 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 Tis, a?.x of a?[x] van het overeenkomstige null-waardetype T?is. Als u een expressie van het type Tnodig 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 lengthwijst ^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 ^emoet 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..bmoeten 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 aan a..^0
  • ..b is gelijk aan 0..b
  • .. is gelijk aan 0..^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.

Zie ook