Szukaj…


Wprowadzenie

W języku C # operator jest elementem programu, który jest stosowany do jednego lub większej liczby operandów w wyrażeniu lub instrukcji. Operatory, które przyjmują jeden operand, takie jak operator inkrementacji (++) lub nowy, są nazywane operatorami jednoargumentowymi. Operatory, które pobierają dwa operandy, takie jak operatory arytmetyczne (+, -, *, /), są nazywane operatorami binarnymi. Jeden operator, operator warunkowy (? :), przyjmuje trzy operandy i jest jedynym operatorem potrójnym w języku C #.

Składnia

  • public static OperandType operator operatorSymbol (OperandType operand1)
  • public static OperandType operator operatorSymbol (OperandType operand1, OperandType2 operand2)

Parametry

Parametr Detale
operatorSymbol Operator jest przeciążony, np. +, -, /, *
OperandType Typ, który zostanie zwrócony przez przeciążonego operatora.
operand 1 Pierwszy operand używany podczas wykonywania operacji.
operand2 Drugi operand używany podczas wykonywania operacji binarnych.
sprawozdania Opcjonalny kod potrzebny do wykonania operacji przed zwróceniem wyniku.

Uwagi

Wszystkie operatory są zdefiniowane jako static methods i nie są virtual i nie są dziedziczone.

Priorytet operatora

Wszyscy operatorzy mają szczególny „priorytet” w zależności od grupy, do której należy operator (operatorzy z tej samej grupy mają taki sam priorytet). Oznacza to, że niektórzy operatorzy zostaną zastosowani przed innymi. Poniżej znajduje się lista grup (zawierająca ich odpowiednie operatory) uporządkowanych według pierwszeństwa (najpierw najwyższa):

  • Główni operatorzy

    • ab - Dostęp członka.
    • a?.b - Brak warunkowego dostępu członka.
    • -> - Dereferencje wskaźników połączone z dostępem członków.
    • f(x) - Wywołanie funkcji.
    • a[x] - Indeksator.
    • a?[x] - Null warunkowy indeksator.
    • x++ - Przyrost Postfiksa.
    • x-- - x-- Postfix.
    • new - Tworzenie instancji.
    • default(T) - Zwraca domyślną zainicjowaną wartość typu T
    • typeof - Zwraca obiekt Type operandu.
    • checked - umożliwia numeryczne sprawdzanie przepełnienia.
    • unchecked - wyłącza numeryczne sprawdzanie przepełnienia.
    • delegate - Deklaruje i zwraca instancję delegata.
    • sizeof - Zwraca rozmiar w bajtach argumentu typu.
  • Unary Operators

    • +x - Zwraca x .
    • -x - Negacja numeryczna.
    • !x - Logiczna negacja.
    • ~x - Bitowe uzupełnienie / deklaracja destruktorów.
    • ++x - Przyrost prefiksu.
    • --x - --x prefiksu.
    • (T)x - Typ odlewu.
    • await - oczekuje na Task .
    • &x - Zwraca adres (wskaźnik) x .
    • *x - Dereferencje wskaźnika.
  • Operatory multiplikatywne

    • x * y - Mnożenie.
    • x / y - Podział.
    • x % y - moduł.
  • Operatory addytywne

    • x + y - Dodawanie.
    • x – y - odejmowanie.
  • Operatory zmiany bitowej

    • x << y - Przesunięcie bitów w lewo.
    • x >> y - Przesunięcie bitów w prawo.
  • Operatory relacji / testowania typu

    • x < y - mniej niż.
    • x > y - Większy niż.
    • x <= y - mniejsza lub równa.
    • x >= y - Większy lub równy.
    • is - Kompatybilność typów.
    • as - Konwersja typu.
  • Operatorzy równości

    • x == y - Równość.
    • x != y - Nie równe.
  • Logiczny operator AND

    • x & y - logiczne / bitowe ORAZ.
  • Logiczny operator XOR

    • x ^ y - Logiczny / bitowy XOR.
  • Logiczny operator OR

    • x | y - logiczne / bitowe LUB.
  • Warunkowe ORAZ Operator

    • x && y - logiczne zwarcie AND.
  • Operator warunkowy LUB

    • x || y - logiczne zwarcie OR.
  • Operator zerowo-koalescencyjny

    • x ?? y - Zwraca x jeśli nie jest null; w przeciwnym razie zwraca y .
  • Operator warunkowy

    • x ? y : z - ocenia / zwraca y jeśli x jest prawdą; w przeciwnym razie ocenia z .

powiązana zawartość

Przeciążeni operatorzy

C # pozwala typom zdefiniowanym przez użytkownika przeciążać operatorów, definiując statyczne funkcje składowe za pomocą słowa kluczowego operator .
Poniższy przykład ilustruje implementację operatora + .

Jeśli mamy Complex klasy, która reprezentuje liczbę zespoloną:

public struct Complex
{
    public double Real { get; set; }
    public double Imaginary { get; set; }
}

I chcemy dodać opcję użycia operatora + dla tej klasy. to znaczy:

Complex a = new Complex() { Real = 1, Imaginary = 2 };
Complex b = new Complex() { Real = 4, Imaginary = 8 };
Complex c = a + b;

Będziemy musieli przeciążyć operatora + dla klasy. Odbywa się to za pomocą funkcji statycznej i słowa kluczowego operator :

public static Complex operator +(Complex c1, Complex c2)
{
   return new Complex 
   { 
       Real = c1.Real + c2.Real,
       Imaginary = c1.Imaginary + c2.Imaginary 
   };
}

Operatory takie jak + , - , * , / mogą być przeciążone. Obejmuje to również Operatory, które nie zwracają tego samego typu (na przykład == i != Mogą zostać przeciążone, pomimo zwracania boolanów) Tutaj obowiązuje również poniższa reguła dotycząca par.

Operatory porównania muszą być przeciążone parami (np. Jeśli < jest przeciążony, > również musi zostać przeciążony).

Pełna lista operatorów przeciążalnych (jak również operatorów nieobciążalnych i ograniczeń nałożonych na niektórych operatorów przeciążalnych) znajduje się w MSDN - Operatory przeciążalne (Podręcznik programowania w języku C #) .

7.0

przeciążenie operator is zostało wprowadzone za pomocą mechanizmu dopasowywania wzorców C # 7.0. Aby uzyskać szczegółowe informacje, patrz Dopasowywanie wzorców

Podany typ Cartesian zdefiniowany w następujący sposób

public class Cartesian
{
    public int X { get; }
    public int Y { get; }
}   

Przeciążalnego operator is można np. Zdefiniować dla współrzędnych Polar

public static class Polar
{
    public static bool operator is(Cartesian c, out double R, out double Theta)
    {
        R = Math.Sqrt(c.X*c.X + c.Y*c.Y);
        Theta = Math.Atan2(c.Y, c.X);
        return c.X != 0 || c.Y != 0;
    }
}

które można wykorzystać w ten sposób

var c = Cartesian(3, 4);
if (c is Polar(var R, *))
{
    Console.WriteLine(R);
}

(Przykład pochodzi z dokumentacji dopasowania wzoru Roslyn )

Operatorzy relacyjni

Równa się

Sprawdza, czy dostarczone argumenty (argumenty) są równe

"a" == "b"     // Returns false.
"a" == "a"     // Returns true.
1 == 0         // Returns false.
1 == 1         // Returns true.
false == true  // Returns false.
false == false // Returns true.

W przeciwieństwie do Javy, operator porównania równości działa natywnie z łańcuchami.

Operator porównania równości będzie działał z operandami różnych typów, jeśli istnieje rzutowanie niejawne z jednego na drugi. Jeśli nie istnieje odpowiednia rzutowana niejawna, możesz wywołać rzutowanie jawne lub użyć metody do konwersji na zgodny typ.

1 == 1.0              // Returns true because there is an implicit cast from int to double.
new Object() == 1.0   // Will not compile.
MyStruct.AsInt() == 1 // Calls AsInt() on MyStruct and compares the resulting int with 1.

W przeciwieństwie do Visual Basic.NET, operator porównania równości nie jest tym samym co operator przypisania równości.

var x = new Object();
var y = new Object();
x == y // Returns false, the operands (objects in this case) have different references.
x == x // Returns true, both operands have the same reference.

Nie mylić z operatorem przypisania ( = ).

W przypadku typów wartości operator zwraca wartość true jeśli oba operandy mają taką samą wartość.
W przypadku typów referencji operator zwraca wartość true jeśli oba operandy są takie same w odniesieniu (nie wartości). Wyjątkiem jest to, że obiekty łańcuchowe będą porównywane z równością wartości.

Nie równa się

Sprawdza, czy dostarczone argumenty nie są równe.

"a" != "b"     // Returns true.
"a" != "a"     // Returns false.
1 != 0         // Returns true.
1 != 1         // Returns false.
false != true  // Returns true.
false != false // Returns false.

var x = new Object();
var y = new Object();
x != y // Returns true, the operands have different references.
x != x // Returns false, both operands have the same reference.

Ten operator skutecznie zwraca wynik przeciwny do wyniku operatora równego ( == )

Lepszy niż

Sprawdza, czy pierwszy operand jest większy niż drugi operand.

3 > 5    //Returns false.
1 > 0    //Returns true.
2 > 2    //Return false.

var x = 10;
var y = 15;
x > y    //Returns false.
y > x    //Returns true.

Mniej niż

Sprawdza, czy pierwszy operand jest mniejszy niż drugi operand.

2 < 4     //Returns true.
1 < -3    //Returns false.
2 < 2     //Return false.

var x = 12;
var y = 22;
x < y    //Returns true.
y < x    //Returns false.

Większy niż równy

Sprawdza, czy pierwszy argument jest większy niż drugi argument.

7 >= 8    //Returns false.
0 >= 0    //Returns true.

Mniej niż równa

Sprawdza, czy pierwszy operand jest mniejszy niż równy drugiemu operandowi.

2 <= 4    //Returns true.
1 <= -3    //Returns false.
1 <= 1     //Returns true. 

Operatory zwierające

Z definicji operatory logiczne zwierające będą oceniać drugi operand tylko wtedy, gdy pierwszy operand nie będzie w stanie określić ogólnego wyniku wyrażenia.

Oznacza to, że jeśli używasz operatora && jako firstCondition && secondCondition , będzie oceniać secondCondition tylko wtedy, gdy firstCondition jest prawdą, a ogólny wynik będzie prawdziwy tylko wtedy, gdy zarówno firstOperand, jak i secondOperand zostaną ocenione jako prawdziwe. Jest to przydatne w wielu scenariuszach, na przykład wyobraź sobie, że chcesz sprawdzić, podczas gdy twoja lista zawiera więcej niż trzy elementy, ale musisz również sprawdzić, czy lista została zainicjowana, aby nie działała w NullReferenceException . Możesz to osiągnąć jak poniżej:

bool hasMoreThanThreeElements = myList != null && mList.Count > 3;

mList.Count> 3 nie będzie sprawdzane, dopóki myList! = null nie zostanie spełniony.

Logiczne AND

&& jest zwartym odpowiednikiem standardowego operatora logicznego AND ( & ).

var x = true;
var y = false;

x && x // Returns true.
x && y // Returns false (y is evaluated).
y && x // Returns false (x is not evaluated).
y && y // Returns false (right y is not evaluated).

Logiczne OR

|| jest zwartym odpowiednikiem standardowego operatora logicznego OR ( | ).

var x = true;
var y = false;

x || x // Returns true (right x is not evaluated).
x || y // Returns true (y is not evaluated).
y || x // Returns true (x and y are evaluated).
y || y // Returns false (y and y are evaluated).

Przykładowe użycie

if(object != null && object.Property)
// object.Property is never accessed if object is null, because of the short circuit.
    Action1();
else
    Action2();

rozmiar

Zwraca int gospodarstwa o wielkości typu * w bajtach.

sizeof(bool)    // Returns 1.
sizeof(byte)    // Returns 1.
sizeof(sbyte)   // Returns 1.
sizeof(char)    // Returns 2.
sizeof(short)   // Returns 2.
sizeof(ushort)  // Returns 2.
sizeof(int)     // Returns 4.
sizeof(uint)    // Returns 4.
sizeof(float)   // Returns 4.
sizeof(long)    // Returns 8.
sizeof(ulong)   // Returns 8.
sizeof(double)  // Returns 8.
sizeof(decimal) // Returns 16.

* Obsługuje tylko niektóre pierwotne typy w bezpiecznym kontekście.

W niebezpiecznym kontekście sizeof może być użyty do zwrócenia rozmiaru innych pierwotnych typów i struktur.

public struct CustomType
{
    public int value;
}

static void Main()
{
    unsafe
    {
        Console.WriteLine(sizeof(CustomType)); // outputs: 4
    }
}

Przeciążanie operatorów równości

Przeciążenie tylko operatorów równości nie wystarczy. W różnych okolicznościach można wywołać wszystkie następujące elementy:

  1. object.Equals i object.GetHashCode
  2. IEquatable<T>.Equals (opcjonalnie, pozwala uniknąć boksu)
  3. operator == i operator != (opcjonalnie, pozwala na użycie operatorów)

Kiedy przesłanianie Equals , GetHashCode musi być nadpisane. Przy wdrażaniu Equals istnieje wiele specjalnych przypadków: porównywanie z obiektami innego typu, porównywanie do siebie itp.

Gdy NIE zostanie zastąpiona metoda Equals i operator == zachowują się inaczej dla klas i struktur. W przypadku klas porównuje się tylko odniesienia, a dla struktur wartości właściwości porównuje się poprzez odbicie, co może negatywnie wpłynąć na wydajność. == nie można używać do porównywania struktur, chyba że zostanie zastąpione.

Zasadniczo operacja równości musi być zgodna z następującymi zasadami:

  • Nie wolno rzucać wyjątków .
  • Refleksyjność: A zawsze równa się A (może nie być prawdziwe dla wartości NULL w niektórych systemach).
  • Przejściowość: jeśli A jest równe B , a B jest równe C , to A jest równe C
  • Jeśli A jest równe B , to A i B mają jednakowe kody skrótu.
  • Niezależność drzewa dziedziczenia: jeśli B i C są instancjami Class2 odziedziczonymi z Class1 : Class1.Equals(A,B) muszą zawsze zwracać tę samą wartość, co wywołanie Class2.Equals(A,B) .
class Student : IEquatable<Student>
{
    public string Name { get; set; } = "";

    public bool Equals(Student other)
    {
        if (ReferenceEquals(other, null)) return false;
        if (ReferenceEquals(other, this)) return true;
        return string.Equals(Name, other.Name);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;

        return Equals(obj as Student);
    }

    public override int GetHashCode()
    {
        return Name?.GetHashCode() ?? 0;
    }

    public static bool operator ==(Student left, Student right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(Student left, Student right)
    {
        return !Equals(left, right);
    }
}

Operatorzy składający klasę: dostęp dla członków

var now = DateTime.UtcNow;
//accesses member of a class.  In this case the UtcNow property.

Operatorzy składający klasę: zerowy warunkowy dostęp do składowych

var zipcode = myEmployee?.Address?.ZipCode;
//returns null if the left operand is null.  
//the above is the equivalent of:
var zipcode = (string)null;
if (myEmployee != null && myEmployee.Address != null)
    zipcode = myEmployee.Address.ZipCode;

Operatory składowe klasy: Wywołanie funkcji

var age = GetAge(dateOfBirth);
//the above calls the function GetAge passing parameter dateOfBirth.

Operatorzy składający klasę: Agregowanie indeksowania obiektów

var letters = "letters".ToCharArray();
char letter = letters[1];
Console.WriteLine("Second Letter is {0}",letter);
//in the above example we take the second character from the array
//by calling letters[1]
//NB: Array Indexing starts at 0; i.e. the first letter would be given by letters[0].

Operatory składowe klasy: zerowe indeksowanie warunkowe

var letters = null;
char? letter = letters?[1];
Console.WriteLine("Second Letter is {0}",letter);
//in the above example  rather than throwing an error because letters is null
//letter is assigned the value null

Operator „Exclusive or”

Operator „wyłączności lub” (w skrócie XOR) to: ^

Ten operator zwraca wartość true, gdy jeden, ale tylko jeden z dostarczonych booli jest prawdziwy.

true ^ false   // Returns true
false ^ true   // Returns true
false ^ false  // Returns false
true ^ true    // Returns false

Operatory zmiany bitów

Operatory shift umożliwiają programistom dostosowanie liczby całkowitej poprzez przesunięcie wszystkich jej bitów w lewo lub w prawo. Poniższy diagram pokazuje wpływ przesunięcia wartości w lewo o jedną cyfrę.

Shift w lewo

uint value = 15;              // 00001111
 
uint doubled = value << 1;    // Result = 00011110 = 30
uint shiftFour = value << 4;  // Result = 11110000 = 240

Shift w prawo

uint value = 240;             // 11110000
 
uint halved = value >> 1;     // Result = 01111000 = 120
uint shiftFour = value >> 4;  // Result = 00001111 = 15

Operatory rzutowania niejawnego i jawnego

C # pozwala typom zdefiniowanym przez użytkownika kontrolować kontrolę przypisania i rzutowania za pomocą explicit i implicit słów kluczowych. Podpis metody ma postać:

public static <implicit/explicit> operator <ResultingType>(<SourceType> myType)

Metoda nie może przyjmować więcej argumentów ani nie może być metodą instancji. Może jednak uzyskać dostęp do dowolnych prywatnych członków typu, w którym jest zdefiniowany.

Przykładem zarówno w implicit i explicit obsadzie:

public class BinaryImage 
{
    private bool[] _pixels;

    public static implicit operator ColorImage(BinaryImage im)
    {
        return new ColorImage(im);
    }

    public static explicit operator bool[](BinaryImage im)
    {
        return im._pixels;
    }
}

Zezwalanie na następującą składnię rzutowania:

var binaryImage = new BinaryImage();
ColorImage colorImage = binaryImage; // implicit cast, note the lack of type 
bool[] pixels = (bool[])binaryImage; // explicit cast, defining the type

Operatorzy rzutowania mogą pracować w obie strony, przechodząc od typu i przechodząc do typu:

public class BinaryImage
{
    public static explicit operator ColorImage(BinaryImage im)
    {
        return new ColorImage(im);
    }

    public static explicit operator BinaryImage(ColorImage cm)
    {
        return new BinaryImage(cm);
    }
}

Wreszcie słowo kluczowe as , które może być zaangażowane w rzutowanie w hierarchii typów, nie jest prawidłowe w tej sytuacji. Nawet po zdefiniowaniu explicit lub implicit rzutowania nie można wykonać:

ColorImage cm = myBinaryImage as ColorImage;

Wygeneruje błąd kompilacji.

Operatory binarne z przypisaniem

C # ma kilka operatorów, które można łączyć ze znakiem = celu oceny wyniku operatora, a następnie przypisania wyniku do oryginalnej zmiennej.

Przykład:

x += y

jest taki sam jak

x = x + y

Operatorzy przydziału:

  • +=
  • -=
  • *=
  • /=
  • %=
  • &=
  • |=
  • ^=
  • <<=
  • >>=

? : Operator trójskładnikowy

Zwraca jedną z dwóch wartości w zależności od wartości wyrażenia logicznego.

Składnia:

condition ? expression_if_true : expression_if_false;

Przykład:

string name = "Frank";
Console.WriteLine(name == "Frank" ? "The name is Frank" : "The name is not Frank");

Operator trójskładnikowy jest asocjacyjnie prawostronny, co pozwala na użycie złożonych wyrażeń trójskładnikowych. Odbywa się to poprzez dodanie dodatkowych równań trójskładnikowych w prawdziwej lub fałszywej pozycji macierzystego równania trójskładnikowego. Należy dołożyć starań, aby zapewnić czytelność, ale w niektórych przypadkach może to być przydatne.

W tym przykładzie złożona operacja trójskładnikowa ocenia funkcję clamp i zwraca bieżącą wartość, jeśli jest w zakresie, wartość min jeśli jest poniżej zakresu, lub wartość max jeśli jest powyżej zakresu.

light.intensity = Clamp(light.intensity, minLight, maxLight);

public static float Clamp(float val, float min, float max)
{
    return (val < min) ? min : (val > max) ? max : val;
}

Można również zagnieżdżać operatory trójskładnikowe, takie jak:

a ? b ? "a is true, b is true" : "a is true, b is false" : "a is false"

// This is evaluated from left to right and can be more easily seen with parenthesis:

a ? (b ? x : y) : z

// Where the result is x if a && b, y if a && !b, and z if !a

Podczas pisania złożonych instrukcji potrójnych często używa się nawiasów lub wcięć, aby poprawić czytelność.

Typy wyrażenie_jeśli_prawda i wyrażenie_jeśli_fałsz muszą być identyczne lub musi nastąpić niejawna konwersja z jednej na drugą.

condition ? 3 : "Not three"; // Doesn't compile because `int` and `string` lack an implicit conversion.

condition ? 3.ToString() : "Not three"; // OK because both possible outputs are strings.

condition ? 3 : 3.5; // OK because there is an implicit conversion from `int` to `double`. The ternary operator will return a `double`.

condition ? 3.5 : 3; // OK because there is an implicit conversion from `int` to `double`. The ternary operator will return a `double`.

Wymagania dotyczące typu i konwersji dotyczą również własnych klas.

public class Car
{}

public class SportsCar : Car
{}

public class SUV : Car
{}

condition ? new SportsCar() : new Car(); // OK because there is an implicit conversion from `SportsCar` to `Car`. The ternary operator will return a reference of type `Car`.

condition ? new Car() : new SportsCar(); // OK because there is an implicit conversion from `SportsCar` to `Car`. The ternary operator will return a reference of type `Car`.

condition ? new SportsCar() : new SUV(); // Doesn't compile because there is no implicit conversion from `SportsCar` to SUV or `SUV` to `SportsCar`. The compiler is not smart enough to realize that both of them have an implicit conversion to `Car`.

condition ? new SportsCar() as Car : new SUV() as Car; // OK because both expressions evaluate to a reference of type `Car`. The ternary operator will return a reference of type `Car`.

typ

Pobiera obiekt System.Type dla typu.

System.Type type = typeof(Point)        //System.Drawing.Point      
System.Type type = typeof(IDisposable)  //System.IDisposable
System.Type type = typeof(Colors)       //System.Drawing.Color
System.Type type = typeof(List<>)       //System.Collections.Generic.List`1[T]

Aby uzyskać typ wykonania, użyj metody GetType celu uzyskania System.Type bieżącej instancji.

Operator typeof przyjmuje nazwę typu jako parametr, który jest określony podczas kompilacji.

public class Animal {} 
public class Dog : Animal {}

var animal = new Dog();

Assert.IsTrue(animal.GetType() == typeof(Animal)); // fail, animal is typeof(Dog) 
Assert.IsTrue(animal.GetType() == typeof(Dog));    // pass, animal is typeof(Dog)
Assert.IsTrue(animal is Animal);                   // pass, animal implements Animal

domyślny operator

Typ wartości (gdzie T: struct)

Wbudowane prymitywne typy danych, takie jak char , int i float , a także typy zdefiniowane przez użytkownika zadeklarowane za pomocą struct lub enum . Ich wartością domyślną jest new T() :

default(int)            // 0
default(DateTime)       // 0001-01-01 12:00:00 AM
default(char)           // '\0' This is the "null character", not a zero or a line break.
default(Guid)           // 00000000-0000-0000-0000-000000000000
default(MyStruct)       // new MyStruct()

// Note: default of an enum is 0, and not the first *key* in that enum
// so it could potentially fail the Enum.IsDefined test
default(MyEnum)         // (MyEnum)0

Typ odniesienia (gdzie T: klasa)

Dowolny typ class , interface , tablicy lub delegata. Ich wartość domyślna to null :

default(object)         // null
default(string)         // null
default(MyClass)        // null
default(IDisposable)    // null
default(dynamic)        // null

nazwa operatora

Zwraca ciąg znaków, który reprezentuje niekwalifikowaną nazwę variable , type lub member .

int counter = 10;
nameof(counter); // Returns "counter"
Client client = new Client();
nameof(client.Address.PostalCode)); // Returns "PostalCode"

nameof operator wprowadza C # 6.0. Jest on oceniany w czasie kompilacji, a zwrócona wartość ciągu jest wstawiana przez kompilator, więc można go użyć w większości przypadków, w których można zastosować ciąg stały (np. Etykiety case w instrukcji switch , atrybuty itp. .). Może być przydatny w przypadkach takich jak zgłaszanie wyjątków i rejestrowanie wyjątków, atrybutów, linków MVC Action itp.

? (Zerowy operator warunkowy)

6.0

Wprowadzony w C # 6.0 , NULL Operator warunkowy ?. natychmiast zwróci null jeśli wyrażenie po lewej stronie ma null , zamiast NullReferenceException . Jeśli jego lewa strona ma wartość inną niż null , jest traktowana jak normalna . operator. Zwróć uwagę, że ponieważ może zwracać null , jego typem zwracanym jest zawsze typ zerowalny. Oznacza to, że dla typu struct lub prymitywnego jest on zawinięty w Nullable<T> .

var bar = Foo.GetBar()?.Value; // will return null if GetBar() returns null
var baz = Foo.GetBar()?.IntegerValue; // baz will be of type Nullable<int>, i.e. int?

Jest to przydatne podczas strzelania z wydarzeń. Zwykle należy zawrzeć wywołanie zdarzenia w instrukcji if sprawdzając, czy nie ma null a następnie podnieść zdarzenie, co wprowadza możliwość wystąpienia wyścigu. Za pomocą operatora warunkowego Null można to naprawić w następujący sposób:

event EventHandler<string> RaiseMe;
RaiseMe?.Invoke("Event raised");

Zwiększanie i zmniejszanie Postfix i Prefix

Przyrost Postfixa X++ doda 1 do x

var x = 42;
x++;
Console.WriteLine(x); // 43

Zmniejszenie Postfiksa X-- odejmie jeden

var x = 42
x--; 
Console.WriteLine(x); // 41

++x nazywa się przyrostem przedrostka, zwiększa wartość x, a następnie zwraca x, podczas gdy x++ zwraca wartość x, a następnie zwiększa

var x = 42;
Console.WriteLine(++x); // 43
System.out.println(x); // 43

podczas

var x = 42;
Console.WriteLine(x++); // 42
System.out.println(x); // 43

oba są powszechnie używane w pętli for

for(int i = 0; i < 10; i++)
{
}

=> Operator Lambda

3.0

Operator => ma taki sam priorytet jak operator przypisania = i jest skojarzony z prawą stroną.

Służy do deklarowania wyrażeń lambda, a także jest szeroko stosowany w zapytaniach LINQ :

string[] words = { "cherry", "apple", "blueberry" };

int shortestWordLength = words.Min((string w) => w.Length); //5

W przypadku użycia w rozszerzeniach lub zapytaniach LINQ typ obiektów można zwykle pominąć, jak to wywnioskował kompilator:

int shortestWordLength = words.Min(w => w.Length); //also compiles with the same result

Ogólna postać operatora lambda jest następująca:

(input parameters) => expression

Parametry wyrażenia lambda są określone przed operatorem => , a rzeczywiste wyrażenie / instrukcja / blok do wykonania znajduje się po prawej stronie operatora:

// expression
(int x, string s) => s.Length > x

// expression
(int x, int y) => x + y

// statement
(string x) => Console.WriteLine(x)

// block
(string x) => {
        x += " says Hello!";
        Console.WriteLine(x);
    }

Tego operatora można użyć do łatwego definiowania uczestników, bez pisania jawnej metody:

delegate void TestDelegate(string s);

TestDelegate myDelegate = s => Console.WriteLine(s + " World");

myDelegate("Hello");

zamiast

void MyMethod(string s)
{
    Console.WriteLine(s + " World");
}

delegate void TestDelegate(string s);

TestDelegate myDelegate = MyMethod;

myDelegate("Hello");

Operator przypisania „=”

Operator przypisania = ustawia wartość operandu lewej ręki na wartość operandu prawej ręki i zwraca tę wartość:

int a = 3;     // assigns value 3 to variable a
int b = a = 5; // first assigns value 5 to variable a, then does the same for variable b
Console.WriteLine(a = 3 + 4); // prints 7

?? Operator zerowo-koalescencyjny

Operator Null-Coalescing ?? zwróci lewą stronę, gdy nie jest zerowa. Jeśli ma wartość zero, zwróci prawą stronę.

object foo = null;
object bar = new object();

var c = foo ?? bar;
//c will be bar since foo was null

?? operator może zostać połączony w łańcuch, co umożliwia usunięcie czeków if .

//config will be the first non-null returned.
var config = RetrieveConfigOnMachine() ??
             RetrieveConfigFromService() ??
             new DefaultConfiguration();


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow