Operator dan ekspresi akses anggota - operator titik, pengindeks, dan pemanggilan.

Anda menggunakan beberapa operator dan ekspresi untuk mengakses anggota jenis. Operator ini termasuk akses anggota (.), elemen array atau akses pengindeks ([]), index-from-end (^), range (..), null-conditional operators (?. dan ?[]), dan method invocation (()). Ini termasuk operator akses anggota null-conditional (?.), dan akses pengindeks (?[]).

Ekspresi akses anggota .

Anda menggunakan token . untuk mengakses anggota dari namespace layanan atau jenis, seperti yang ditunjukkan contoh berikut:

  • Gunakan . untuk mengakses namespace layanan berlapis dalam sebuah namespace layanan, seperti yang ditunjukkan contoh using direktif berikut:
using System.Collections.Generic;
  • Gunakan . untuk membentuk nama yang memenuhi syarat untuk mengakses jenis dalam namespace layanan, seperti yang ditunjukkan oleh kode berikut:
System.Collections.Generic.IEnumerable<int> numbers = [1, 2, 3];

Gunakan usingdirektif untuk memanfaatkan nama yang memenuhi syarat opsional.

  • Gunakan . untuk mengakses anggota jenis, statis dan non-statis, seperti yang ditunjukkan oleh kode berikut:
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

Anda juga dapat menggunakan . untuk mengakses metode ekstensi.

Operator pengindeks []

Kurung siku, [], biasanya digunakan untuk mengakses elemen array, pengindeks, atau penunjuk.

Mengakses array

Contoh berikut menunjukkan cara mengakses elemen array:

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

Jika indeks array berada di luar batas dimensi array yang sesuai, maka IndexOutOfRangeException akan dilemparkan.

Seperti yang ditunjukkan contoh sebelumnya, Anda juga menggunakan kurung siku saat mendeklarasikan jenis array atau untuk instansiasi instans array.

Untuk informasi selengkapnya tentang array, lihat Array.

Mengakses pengindeks

Contoh berikut menggunakan jenis Dictionary<TKey,TValue> .NET untuk menunjukkan akses pengindeks:

var dict = new Dictionary<string, double>();
dict["one"] = 1;
dict["pi"] = Math.PI;
Console.WriteLine(dict["one"] + dict["pi"]);  // output: 4.14159265358979

Pengindeks memungkinkan Anda mengindeks instans jenis yang ditentukan pengguna dengan cara yang sama seperti pengindeksan array. Tidak seperti indeks array, yang harus berupa bilangan bulat, parameter pengindeks dapat dideklarasikan berdasarkan jenis apa pun.

Untuk informasi selengkapnya tentang pengindeks, lihat Pengindeks.

Penggunaan lainnya dari []

Untuk informasi tentang akses elemen penunjuk, lihat bagian Operator akses elemen Penunjuk [] dari artikel Operator terkait Penunjuk.

Anda juga menggunakan kurung siku untuk menentukan atribut:

[System.Diagnostics.Conditional("DEBUG")]
void TraceMethod() {}

Operator ?. null-conditional dan ?[]

Operator null-conditional menerapkan operasi akses anggota (?.) atau akses elemen (?[]) ke operand-nya hanya jika operand tersebut mengevaluasi ke non-null; jika tidak, itu mengembalikan null. Yaitu:

  • Jika a mengevaluasi ke null, hasil dari a?.x atau a?[x] adalah null.

  • Jika a mengevaluasi ke bukan null, hasil dari a?.x atau a?[x] sama dengan hasil dari a.x atau a[x], berturut-turut.

    Catatan

    Jika a.x atau a[x] melempar pengecualian, a?.x atau a?[x] akan melemparkan pengecualian yang sama untuk a bukan null. Misalnya, jika a adalah instans array bukan null dan x berada di luar batas a, a?[x] akan melemparkan IndexOutOfRangeException.

Operator null-kondisional memiliki sirkuit pendek. Artinya, jika satu operasi dalam rantai anggota kondisional atau operasi akses elemen mengembalikan null, sisa rantai tidak dijalankan. Dalam contoh berikut, B tidak dievaluasi jika A dievaluasi ke null dan C tidak dievaluasi jika A atau B mengevaluasi ke null:

A?.B?.Do(C);
A?.B?[C];

Jika A mungkin null tetapi B dan C tidak akan null jika A tidak null, Anda hanya perlu menerapkan operator null-conditional ke A:

A?.B.C();

Dalam contoh sebelumnya, B tidak dievaluasi dan C() tidak dipanggil jika A null. Namun, jika akses anggota berantai terganggu, misalnya oleh tanda kurung seperti dalam (A?.B).C(), sirkuit pendek tidak terjadi.

Contoh berikut menunjukkan penggunaan operator ?. dan ?[]:

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}");
}

Contoh pertama dari dua contoh sebelumnya juga menggunakan operator penggabungan null?? untuk menentukan ekspresi alternatif untuk melakukan evaluasi jika hasil operasi null-kondisional adalah null.

Jika a.x atau a[x] berjenis nilai yang tidak dapat diubah ke null T, a?.x atau a?[x] merupakan jenis nilai yang dapat diubah ke nullT? yang sesuai. Jika Anda memerlukan ekspresi jenis T, terapkan operator penggabungan null ?? ke ekspresi null-kondisional, seperti yang ditunjukkan contoh berikut:

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

Dalam contoh sebelumnya, jika Anda tidak menggunakan operator ??, numbers?.Length < 2 melakukan evaluasi ke false saat numbers adalah null.

Catatan

Operator ?. mengevaluasi operand sebelah kirinya tidak lebih dari sekali, menjamin bahwa operasi tidak dapat diubah menjadi null setelah diverifikasi sebagai bukan null.

Operator akses anggota null-kondisional ?. juga dikenal sebagai operator Elvis.

Pemanggilan delegasi utas-aman

Gunakan operator ?. untuk memeriksa apakah delegasi merupakan bukan null dan panggil dengan cara utas-aman (misalnya, saat Anda menaikkan peristiwa), seperti yang ditunjukkan oleh kode berikut:

PropertyChanged?.Invoke(…)

Kode tersebut setara dengan kode berikut:

var handler = this.PropertyChanged;
if (handler != null)
{
    handler(…);
}

Contoh sebelumnya adalah cara aman utas untuk memastikan bahwa hanya non-null handler yang dipanggil. Karena instans delegasi tidak dapat diubah, tidak ada utas yang dapat mengubah objek yang dirujuk oleh variabel lokal handler. Secara khusus, jika kode yang dijalankan oleh utas lain berhenti berlangganan dari peristiwa PropertyChanged dan PropertyChanged menjadi null sebelum handler dipanggil, objek yang dirujuk oleh handler tetap tidak terpengaruh.

Ekspresi pemanggilan ()

Gunakan tanda kurung, (), untuk memanggil metode atau memanggil delegasi.

Contoh berikut menunjukkan cara memanggil metode, dengan atau tanpa argumen, dan memanggil delegasi:

Action<int> display = s => Console.WriteLine(s);

List<int> numbers =
[
    10,
    17
];
display(numbers.Count);   // output: 2

numbers.Clear();
display(numbers.Count);   // output: 0

Anda juga menggunakan tanda kurung saat memanggil konstruktor dengan operator new.

Penggunaan lainnya dari ()

Anda juga menggunakan tanda kurung untuk menyesuaikan urutan untuk melakukan evaluasi operasi dalam ekspresi. Untuk informasi selengkapnya, lihat Operator C#.

Ekspresi konversi eksplisit, yang melakukan konversi jenis eksplisit, juga menggunakan tanda kurung.

Indeks dari operator akhir ^

Operator indeks dan rentang dapat digunakan dengan jenis yang dapat dihitung. Jenis yang dapat dihitung adalah jenis yang memiliki int properti bernama atau CountLength dengan aksesor yang dapat diakses get . Ekspresi koleksi juga mengandalkanjenis yang dapat dihitung.

Operator ^ menunjukkan posisi elemen dari akhir urutan. Untuk urutan panjang length, ^n menunjuk ke elemen dengan offset length - n dari awal urutan. Misalnya, ^1 menunjuk ke elemen terakhir dari urutan dan ^length menunjuk ke elemen pertama dari urutan.

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

Seperti yang ditunjukkan oleh contoh sebelumnya, ekspresi ^e adalah berjenis System.Index. Dalam ekspresi ^e, hasil dari e harus secara implisit dapat dikonversi ke int.

Anda juga dapat menggunakan operator ^ dengan operator rentang untuk membuat berbagai indeks. Untuk informasi selengkapnya, lihat Indeks dan rentang.

Dimulai dengan C# 13, Indeks dari operator akhir dapat digunakan dalam penginisialisasi objek.

Operator rentang ..

Operator .. menentukan awal dan akhir rentang indeks sebagai operandnya. Operand sebelah kiri adalah awal rentang yang inklusif. Operand kanan adalah akhir rentang yang eksklusif. Salah satu operand dapat menjadi indeks dari awal atau dari akhir urutan, seperti yang ditunjukkan contoh berikut:

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));

Seperti yang ditunjukkan oleh contoh sebelumnya, ekspresi a..b adalah berjenis System.Range. Dalam ekspresi a..b, hasil dari a dan bharus secara implisit dapat dikonversi ke Int32 atau Index.

Penting

Konversi implisit dari int ke Index melempar ArgumentOutOfRangeException ketika nilainya negatif.

Anda dapat menghilangkan salah satu operand dari operator .. untuk mendapatkan rentang terbuka:

  • a.. setara dengan a..^0
  • ..b setara dengan 0..b
  • .. setara dengan 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));

Tabel berikut ini memperlihatkan berbagai cara untuk mengekspresikan rentang pengumpulan:

Ekspresi operator rentang Deskripsi
.. Semua nilai dalam koleksi.
..end Nilai dari awal hingga secara end eksklusif.
start.. Nilai dari secara start inklusif hingga akhir.
start..end Nilai dari secara start inklusif ke end secara eksklusif.
^start.. Nilai dari start secara inklusif ke penghitungan akhir dari akhir.
..^end Nilai dari awal hingga penghitungan end eksklusif dari akhir.
start..^end Nilai dari start secara inklusif hingga end dihitung secara eksklusif dari akhir.
^start..^end Nilai dari start secara inklusif hingga end secara eksklusif keduanya dihitung dari akhir.

Contoh berikut menunjukkan efek penggunaan semua rentang yang disajikan dalam tabel sebelumnya:

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

Untuk informasi selengkapnya, lihat Indeks dan rentang.

Token .. juga digunakan sebagai operator spread dalam ekspresi koleksi.

Kelebihan beban operator

Operator ., (), ^, dan .. tidak dapat kelebihan beban. Operator [] juga dianggap sebagai operator yang tidak boleh kelebihan beban. Gunakan pengindeks untuk mendukung pengindeksan dengan jenis yang ditentukan pengguna.

Spesifikasi bahasa C#

Untuk informasi selengkapnya, lihat bagian berikut dari spesifikasi bahasa C#:

Untuk informasi selengkapnya tentang indeks dan rentang, lihat catatan proposal fitur.

Lihat juga