To bardziej dokumentacja niż prawdziwe pytanie. Wydaje się, że to nie zostało jeszcze rozwiązane w SO (chyba że to przegapiłem), więc oto:
Wyobraź sobie klasę ogólną, która zawiera statyczny element członkowski:
class Foo<T> {
public static int member;
}
Czy istnieje nowe wystąpienie elementu członkowskiego dla każdej określonej klasy, czy też jest tylko jedno wystąpienie dla wszystkich klas typu Foo?
Można to łatwo zweryfikować za pomocą takiego kodu:
Foo<int>.member = 1;
Foo<string>.member = 2;
Console.WriteLine (Foo<int>.member);
Jaki jest wynik i gdzie jest to udokumentowane?
T
używanego (Foo<int>
iFoo<string>
reprezentują dwie różne klasy i każda będzie miała po jednej instancji, ale kilka intencjiFoo<int>
będzie współdzielić jedną instancjęmember
). Bardziej szczegółowy przykład można znaleźć na stronie: stackoverflow.com/a/38369256/336648Odpowiedzi:
static
Pole jest wspólna dla wszystkich wystąpień tego samego typu .Foo<int>
iFoo<string>
są dwa różne typy. Można to udowodnić za pomocą następującego wiersza kodu:// this prints "False" Console.WriteLine(typeof(Foo<int>) == typeof(Foo<string>));
Jeśli chodzi o miejsca, w których jest to udokumentowane, w sekcji 1.6.5 Pola specyfikacji języka C # (dla języka C # 3):
Jak wspomniano wcześniej;
Foo<int>
iFoo<string>
nie są tą samą klasą; są to dwie różne klasy zbudowane z tej samej klasy ogólnej. Jak to się dzieje, opisano w sekcji 4.4 wyżej wymienionego dokumentu:źródło
Foo<int>
iFoo<String>
są różnymi typami w C #, są tego samego typu w Javie ze względu na sposób, w jaki Java radzi sobie z rodzajami (sztuczki typu wymazywanie / kompilator).Problem polega na tym, że „klasy generyczne” w ogóle nie są klasami.
Ogólne definicje klas są tylko szablonami klas i dopóki nie zostaną określone parametry typu, są tylko fragmentem tekstu (lub garścią bajtów).
W czasie wykonywania można określić parametr typu dla szablonu, ożywiając go w ten sposób i tworząc klasę w pełni określonego typu. Dlatego właściwości statyczne nie obejmują całego szablonu i dlatego nie można rzutować między
List<string>
aList<int>
.Ta relacja w pewnym sensie odzwierciedla relację klasy-obiekt. Tak jak klasy nie istnieją * dopóki nie utworzysz z nich instancji obiektu, tak ogólne klasy nie istnieją, dopóki nie utworzysz klasy opartej na szablonie.
PS Można to zadeklarować
class Foo<T> { public static T Member; }
Z tego jest dość oczywiste, że statycznych członków nie można udostępniać, ponieważ T jest różne dla różnych specjalizacji.
źródło
Nie są udostępniane. Nie jestem pewien, gdzie jest to udokumentowane, ale ostrzeżenie analizy CA1000 ( Nie deklaruj statycznych elementów członkowskich w typach ogólnych ) ostrzega przed tym tylko ze względu na ryzyko skomplikowania kodu.
źródło
Implementacja typów ogólnych w języku C # jest bliższa C ++. W obu tych językach
MyClass<Foo>
iMyClass<Bar>
nie współdzielą statycznych elementów członkowskich, ale w Javie tak. W językach C # i C ++MyClass<Foo>
wewnętrznie tworzy całkowicie nowy typ w czasie kompilacji, tak jakby typy generyczne były rodzajem makr. Zazwyczaj można zobaczyć ich wygenerowane nazwy w śladzie stosu, na przykładMyClass'1
iMyClass'2
. Dlatego nie mają wspólnych zmiennych statycznych. W Javie typy generyczne są implementowane przez prostszą metodę generowania kodu przez kompilator przy użyciu typów nieogólnych i dodawania rzutów typów na całym świecie. TakMyClass<Foo>
iMyClass<Bar>
nie generują dwa zupełnie nową klasę w Javie, zamiast oboje są tej samej klasyMyClass
spodu i dlatego oni dzielą zmiennych statycznych.źródło
Tak naprawdę nie są udostępniane. Ponieważ członek w ogóle nie należy do instancji. Statyczny element członkowski klasy należy do samej klasy. Tak więc, jeśli masz MyClass.Number, jest to takie samo dla wszystkich obiektów MyClass.Number, ponieważ nie zależy to nawet od obiektu. Możesz nawet wywołać lub zmodyfikować MyClass.Number bez żadnego obiektu.
Ale ponieważ Foo <int> nie jest tą samą klasą co Foo <string>, te dwie liczby nie są wspólne.
Przykład, aby to pokazać:
TestClass<string>.Number = 5; TestClass<int>.Number = 3; Console.WriteLine(TestClass<string>.Number); //prints 5 Console.WriteLine(TestClass<int>.Number); //prints 3
źródło
IMO, musisz to przetestować, ale tak myślę
Foo<int>.member = 1; Foo<string>.member = 2; Console.WriteLine (Foo<int>.member);
wyświetli wynik,
1
ponieważ myślę, że podczas kompilacji kompilator utworzy 1 klasę dla każdej klasy ogólnej, której używasz (w Twoim przykładzie:Foo<int>
iFoo<string>
).Ale nie jestem w 100% pewien =).
Uwaga: myślę, że używanie tego rodzaju statycznych atrybutów nie jest dobrym projektem ani dobrą praktyką.
źródło