.NET Framework
Typy niestandardowe
Szukaj…
Uwagi
Zwykle struct
jest używana tylko wtedy, gdy wydajność jest bardzo ważna. Ponieważ typy wartości znajdują się na stosie, można uzyskać do nich dostęp znacznie szybciej niż klasy. Jednak na stosie jest znacznie mniej miejsca niż na stosie, więc struktury powinny być małe (Microsoft zaleca, aby struct
zajmowały nie więcej niż 16 bajtów).
class
jest najczęściej używanym typem (z tych trzech) w języku C # i ogólnie jest tym, z czym powinieneś zacząć.
enum
jest używane, gdy można mieć jasno zdefiniowaną, wyraźną listę elementów, które należy zdefiniować tylko raz (w czasie kompilacji). Wyliczenia są pomocne dla programistów jako lekkie odniesienie do pewnej wartości: zamiast definiować listę constant
zmiennych do porównania, możesz użyć wyliczenia i uzyskać wsparcie Intellisense, aby upewnić się, że przypadkowo nie użyjesz niewłaściwej wartości.
Definicja struktury
Struktury dziedziczą z System.ValueType, są typami wartości i są aktywne na stosie. Gdy typy wartości są przekazywane jako parametr, są przekazywane przez wartość.
Struct MyStruct
{
public int x;
public int y;
}
Przekazanie przez wartość oznacza, że wartość parametru jest kopiowana dla metody, a wszelkie zmiany dokonane w parametrze w metodzie nie są odzwierciedlane poza metodą. Rozważmy na przykład następujący kod, który wywołuje metodę o nazwie AddNumbers
, przekazując zmienne a
i b
, które są typu int
, czyli typu Value.
int a = 5;
int b = 6;
AddNumbers(a,b);
public AddNumbers(int x, int y)
{
int z = x + y; // z becomes 11
x = x + 5; // now we changed x to be 10
z = x + y; // now z becomes 16
}
Choć dodaliśmy 5 do x
wewnątrz metody, wartość a
pozostaje niezmieniona, ponieważ jest to typ wartości, a to oznacza x
był kopią a
„s wartości, ale nie faktycznie . a
Pamiętaj, że typy wartości znajdują się na stosie i są przekazywane według wartości.
Definicja klasy
Klasy dziedziczą z System.Object, są typami referencyjnymi i żyją na stercie. Gdy typy referencyjne są przekazywane jako parametr, są przekazywane przez referencję.
public Class MyClass
{
public int a;
public int b;
}
Przekazanie przez referencję oznacza, że referencja do parametru jest przekazywana do metody, a wszelkie zmiany parametru zostaną odzwierciedlone poza metodą po jej zwróceniu, ponieważ referencja dotyczy dokładnie tego samego obiektu w pamięci . Użyjmy tego samego przykładu, co poprzednio, ale najpierw „zawiniemy” int
w klasę.
MyClass instanceOfMyClass = new MyClass();
instanceOfMyClass.a = 5;
instanceOfMyClass.b = 6;
AddNumbers(instanceOfMyClass);
public AddNumbers(MyClass sample)
{
int z = sample.a + sample.b; // z becomes 11
sample.a = sample.a + 5; // now we changed a to be 10
z = sample.a + sample.b; // now z becomes 16
}
Tym razem, kiedy zmieniliśmy sample.a
na 10
, zmienia się również wartość instanceOfMyClass.a
, ponieważ została przekazana przez referencję . Przekazanie przez odwołanie oznacza, że odwołanie (zwane czasem wskaźnikiem ) do obiektu zostało przekazane do metody zamiast kopii samego obiektu.
Pamiętaj, typy referencyjne żyją na stercie i są przekazywane przez referencję.
Definicja wyliczenia
Wyliczenie jest specjalnym rodzajem klasy. enum
kluczowe enum
informuje kompilator, że ta klasa dziedziczy po abstrakcyjnej klasie System.Enum. Wyliczenia służą do tworzenia odrębnych list przedmiotów.
public enum MyEnum
{
Monday = 1,
Tuesday,
Wednesday,
//...
}
Wyliczenie można traktować jako wygodny sposób odwzorowywania stałych na pewne podstawowe wartości. Wyliczenie zdefiniowane powyżej deklaruje wartości dla każdego dnia tygodnia i rozpoczyna się od 1
. Tuesday
automatycznie zostanie zamapowany na 2
, Wednesday
na 3
itd.
Domyślnie wyliczenia używają int
jako typu bazowego i zaczynają się od 0, ale można użyć dowolnego z następujących typów integralnych : byte, sbyte, short, ushort, int, uint, long, or ulong
, i mogą określać jawne wartości dla dowolnego pozycja. Jeśli niektóre elementy są wyraźnie określone, a niektóre nie, każdy element po ostatnim zdefiniowanym będzie zwiększany o 1.
Skorzystalibyśmy z tego przykładu, rzucając inną wartość na MyEnum, taką jak:
MyEnum instance = (MyEnum)3; // the variable named 'instance' gets a
//value of MyEnum.Wednesday, which maps to 3.
int x = 2;
instance = (MyEnum)x; // now 'instance' has a value of MyEnum.Tuesday
Innym przydatnym, choć bardziej złożonym rodzajem wyliczenia są Flags
. Przez zdobienia enum z Flags
atrybutu, można przypisać zmiennej więcej niż jedną wartość w czasie. Zauważ, że robiąc to, musisz wyraźnie zdefiniować wartości w reprezentacji podstawy 2.
[Flags]
public enum MyEnum
{
Monday = 1,
Tuesday = 2,
Wednesday = 4,
Thursday = 8,
Friday = 16,
Saturday = 32,
Sunday = 64
}
Teraz możesz porównywać więcej niż jedną wartość na raz, używając porównań bitowych lub, jeśli używasz .NET 4.0 lub nowszej, wbudowanej metody Enum.HasFlag
.
MyEnum instance = MyEnum.Monday | MyEnum.Thursday; // instance now has a value of
// *both* Monday and Thursday,
// represented by (in binary) 0100.
if (instance.HasFlag(MyEnum.Wednesday))
{
// it doesn't, so this block is skipped
}
else if (instance.HasFlag(MyEnum.Thursday))
{
// it does, so this block is executed
}
Ponieważ klasa Enum jest podklasą z System.ValueType
, jest ona traktowana jako typ wartości i przekazywana przez wartość, a nie przez odwołanie. Obiekt podstawowy jest tworzony na stercie, ale po przekazaniu wartości wyliczenia do wywołania funkcji kopia wartości przy użyciu bazowego typu wartości wyliczenia (zwykle System.Int32) jest wypychana na stos. Kompilator śledzi powiązanie między tą wartością a obiektem podstawowym, który został utworzony na stosie. Aby uzyskać więcej informacji, zobacz ValueType Class (System) (MSDN) .