C# Language
Operatorzy
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ść typuT
-
typeof
- Zwraca obiektType
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
- Zwracax
. -
-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 naTask
. -
&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
- Zwracax
jeśli nie jest null; w przeciwnym razie zwracay
.
-
Operator warunkowy
-
x ? y : z
- ocenia / zwracay
jeślix
jest prawdą; w przeciwnym razie oceniaz
.
-
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 #) .
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:
-
object.Equals
iobject.GetHashCode
-
IEquatable<T>.Equals
(opcjonalnie, pozwala uniknąć boksu) -
operator ==
ioperator !=
(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ściNULL
w niektórych systemach). - Przejściowość: jeśli
A
jest równeB
, aB
jest równeC
, toA
jest równeC
- Jeśli
A
jest równeB
, toA
iB
mają jednakowe kody skrótu. - Niezależność drzewa dziedziczenia: jeśli
B
iC
są instancjamiClass2
odziedziczonymi zClass1
:Class1.Equals(A,B)
muszą zawsze zwracać tę samą wartość, co wywołanieClass2.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)
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
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();