const
i readonly
są podobne, ale nie są dokładnie takie same.
const
Pole jest stałą czasu kompilacji, co oznacza, że wartość ta może być obliczana w czasie kompilacji. readonly
Pole umożliwia dodatkowe scenariusze, w których należy przeprowadzić kilka kod podczas budowy tego typu. Po zakończeniu budowy readonly
pola nie można zmienić.
Na przykład const
członków można używać do definiowania członków, takich jak:
struct Test
{
public const double Pi = 3.14;
public const int Zero = 0;
}
Ponieważ wartości takie jak 3.14 i 0 są stałymi czasów kompilacji. Rozważ jednak przypadek, w którym definiujesz typ i chcesz podać niektóre jego wcześniejsze wersje. Na przykład, możesz chcieć zdefiniować klasę Kolor i podać „stałe” dla typowych kolorów, takich jak Czarny, Biały itp. Nie można tego zrobić z elementami stałymi, ponieważ prawa strona nie jest stała czasu kompilacji. Można to zrobić za pomocą zwykłych elementów statycznych:
public class Color
{
public static Color Black = new Color(0, 0, 0);
public static Color White = new Color(255, 255, 255);
public static Color Red = new Color(255, 0, 0);
public static Color Green = new Color(0, 255, 0);
public static Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}
Ale nie ma nic, co powstrzymałoby klienta Color od zepsucia się nim, być może poprzez zamianę wartości czerni i bieli. Nie trzeba dodawać, że spowodowałoby to konsternację u innych klientów klasy Color. Funkcja „tylko do odczytu” rozwiązuje ten scenariusz.
Po prostu wprowadzając readonly
słowo kluczowe w deklaracjach, zachowujemy elastyczną inicjalizację, jednocześnie zapobiegając pomijaniu kodu klienta.
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
private byte red, green, blue;
public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}
Warto zauważyć, że stałe elementy są zawsze statyczne, podczas gdy element tylko do odczytu może być statyczny lub nie, tak jak zwykłe pole.
Możliwe jest użycie jednego słowa kluczowego do tych dwóch celów, ale prowadzi to do problemów z wersją lub problemów z wydajnością. Załóżmy przez chwilę, że użyliśmy do tego jednego słowa kluczowego (const), a programista napisał:
public class A
{
public static const C = 0;
}
a inny programista napisał kod, który polegał na A:
public class B
{
static void Main() => Console.WriteLine(A.C);
}
Czy generowany kod może polegać na tym, że AC jest stałą czasową kompilacji? Czyli użycie AC można po prostu zastąpić wartością 0? Jeśli powiesz „tak”, oznacza to, że twórca A nie może zmienić sposobu inicjalizacji AC - wiąże to ręce twórcy A bez pozwolenia.
Jeśli powiesz „nie” w tym pytaniu, ważna optymalizacja zostanie pominięta. Być może autor A jest przekonany, że AC zawsze będzie wynosić zero. Użycie zarówno const, jak i readonly pozwala twórcy A określić intencję. To zapewnia lepsze zachowanie wersjonowania, a także lepszą wydajność.
static readonly
: spróbuj użyć stałej w środku,IEnumerator
która wyzwalałaby niemożliwy do sprawdzenia,yield
a dostaniesz przerażający „Wewnętrzny błąd kompilatora” . Nie testowałem kodu poza Unity3D, ale ufam, że jest to błąd mono lub .NET . Jest to jednak problem c # .