Статические члены универсального класса привязаны к конкретному экземпляру?
это скорее документация, чем реальный вопрос. Это, кажется, еще не было рассмотрено на SO (если я не пропустил его), так что здесь идет:
представьте себе универсальный класс, который содержит статические члены:
class Foo<T> {
public static int member;
}
есть ли новый экземпляр члена для каждого конкретного класса, или есть только один экземпляр для всех классов Foo-типа?
Это можно легко проверить с помощью такого кода:
Foo<int>.member = 1;
Foo<string>.member = 2;
Console.WriteLine (Foo<int>.member);
каков результат, и где это поведение задокументировано?
6 ответов:
A
static
поле является общим для всех экземпляров того же типа.Foo<int>
иFoo<string>
два разных типа. Это можно доказать с помощью следующей строки кода:// this prints "False" Console.WriteLine(typeof(Foo<int>) == typeof(Foo<string>));
что касается того, где это задокументировано, то в разделе 1.6.5 поля спецификации языка C# (для C# 3):
статическое поле идентифицирует ровно один место хранения. Сколько бы их ни было экземпляры класса создан, есть только одна копия статическое поле.
как было сказано выше;
Foo<int>
иFoo<string>
не являются одним и тем же классом; это два разных класса, построенных из одного и того же универсального класса. Как это происходит, описано в разделе 4.4 вышеупомянутого документа:объявление универсального типа, само по себе, означает несвязанный универсальный тип используется в качестве "чертежа" для формирования многих различные типы, путем применения тип аргументы.
проблема здесь заключается в том, что "общие классы" вообще не являются классами.
определения общих классов - это просто шаблоны для классов, и до тех пор, пока их параметры типа не будут указаны, они являются просто куском текста (или несколькими байтами).
во время выполнения можно указать параметр типа для шаблона, тем самым оживив его и создав класс теперь полностью указанного типа. Вот почему статические свойства не являются шаблонными, и это почему вы не можете бросить между
List<string>
иList<int>
.это отношение как бы отражает отношение класса-объекта. Точно так же, как классы не существуют* до тех пор, пока вы не создадите экземпляр объекта из них, универсальные классы не существуют, пока вы не создадите класс на основе шаблона.
P. S. Это вполне можно объявить
class Foo<T> { public static T Member; }
из этого очевидно, что статические члены не могут быть разделены, так как T отличается для разных специализаций.
Они не разделяют. Не уверен, где это документально, но анализ предупреждение CA1000 (не объявляйте статические члены в универсальных типах) предупреждает только об этом из-за риска сделать код более сложным.
C# реализация дженериков более близка к C++. На обоих этих языках
MyClass<Foo>
иMyClass<Bar>
не разделяют статические члены, но в Java они делают. В C# и C++MyClass<Foo>
внутренне создает совершенно новый тип во время компиляции, как если бы дженерики были своего рода макросами. Обычно вы можете видеть их сгенерированные имена в трассировке стека, напримерMyClass'1
иMyClass'2
. Вот почему они не разделяют статические переменные. В Java дженерики реализуются более простым методом компилятора, генерирующим код с использованием не универсальные типы и добавление типов приведений по всему. Так чтоMyClass<Foo>
иMyClass<Bar>
Не создавайте два совершенно новых класса в Java, вместо этого они оба являются одним и тем же классомMyClass
внизу и поэтому они разделяют статические переменные.
они на самом деле не разделяются. Потому что член вообще не принадлежит экземпляру. Статический член класса принадлежит самому классу. Итак, если у вас есть MyClass.Это количество является одинаковым для всех класса MyClass.Количество объектов, потому что это даже не зависит от объекта. Вы даже можете вызвать или изменить MyClass.Номер без какого-либо объекта.
но так как Foo не является тем же классом, что и Foo, эти два числа не являются общими.
пример для показа это:
TestClass<string>.Number = 5; TestClass<int>.Number = 3; Console.WriteLine(TestClass<string>.Number); //prints 5 Console.WriteLine(TestClass<int>.Number); //prints 3
ИМО, вы должны проверить его, но я думаю, что
Foo<int>.member = 1; Foo<string>.member = 2; Console.WriteLine (Foo<int>.member);
выводит
1
потому что я думаю, что во время компиляции компилятор создает 1 класс для каждого универсального класса, который вы используете (в вашем примере:Foo<int>
иFoo<string>
).но я не уверен на 100%=).
примечание: Я думаю, что это не хороший дизайн и не хорошая практика использовать такие статические атрибуты.