Przejdź do treści

DevStyle - Strona Główna
“const” vs “static readonly”

“const” vs “static readonly”

Maciej Aniserowicz

6 czerwca 2008

Backend

Składowe klasy, których niezmienności jesteśmy pewni, możemy oznaczyć przynajmniej dwojako:

 1:   public class ConstantValues
2: {
3: public const int Constant = 666;
4: public static readonly int StaticReadonly = 123;
5: }

Efekt ich wykorzystania jest taki sam – mamy dostęp do przypisanych im wartości spoza klasy, jednak nie możemy ich zmienić. Dokładne znaczenie: const to “wartość stała”, a static readonly to “składowa statyczna tylko do odczytu” Konstrukcje te jednak różnią się kilkoma szczegółami. Poniżej wymieniam parę, które aktualnie przyszły mi do głowy. Być może różnic jest więcej, ale i tak najważniejszą zostawiłem na koniec:

1. Składowa readonly może być zainicjowana przy deklaracji LUB w statycznym konstruktorze, ważne, aby miało to miejsce dokładnie jeden raz (czyli możemy przypisać wartość wyliczoną przez statyczną metodę). Z kolei składowa const musi być zainicjowana przy deklaracji za pomocą literału napisowego, liczby, bądź wartości boolowskiej.

2. Tylko składowe const mogą posłużyć jako argumenty w deklaracji użycia atrybutu, czyli to się skompiluje

 1:   [SomeAttribute(ConstantValues.Constant)]
2: void SomeMethod() { }

a to już nie:

 1:   [SomeAttribute(ConstantValues.StaticReadonly)]
2: void SomeMethod() { }

3. Najważniejsze: wartości const są podmieniane w czasie kompilacji, podczas gdy wartości static są pobierane podczas działania programu! Najpierw dowód, a potem uzasadnienie “dlaczego to takie ważne”:

 1:   int constant;
2: int staticReadonly;
3: void UseConstants()
4: {
5: constant = ConstantValues.Constant;
6: staticReadonly = ConstantValues.StaticReadonly;
7: }

Po skompilowaniu ciało powyższej metody przedstawia się w Reflectorze następująco:

 1:   private void UseConstants()
2: {
3: this.constant = 0x29a;
4: this.staticReadonly = ConstantValues.StaticReadonly;
5: }

I cóż się okazało? Zamiast ConstantValues.Constant mamy 0x29a, czyli nieświęte 666 w hexach, z pominięciem odwołania do klasy zawierającej tą wartość!
Dobra, “no i co z tego?”. Wyobraźmy sobie sytuację, gdy ten przygłupi prymitywny przykład jest częścią bardziej rozbudowanego systemu. Klasa ConstantValues znajduje się w ConstantAssembly.dll, natomiast wartości z niej są pobierane przez algorytmy w Algorithms.dll. W sytuacji, gdy chcemy zmienić wartość składowej ConstantValues.StaticReadonly wszystko jest ok – podmieniamy na co nam trzeba, kompilujemy ConstantAssembly.dll, wrzucamy nową wersję i wszystko śmiga. Co się jednak dzieje, gdy chcemy zmodyfikować ConstantValues.Constant? Podmiana ConstantAssembly.dll nic nie zmienia! Musimy przekompilować nie tylko ConstantAssembly, ale również wszystkie biblioteki z niej korzystające, ponieważ to właśnie podczas KOMPILACJI pobierane i podstawiane są te wartości! Dlatego też trzeba zdawać sobie sprawę z owej różnicy i świadomie stosować odpowiednie rozwiązania. Metodzie “chybił-trafił” mówimy stanowcze i zdecydowane NIE!

Zobacz również