Связаны ли статические члены универсального класса с конкретным экземпляром? - PullRequest
74 голосов
/ 14 июня 2010

Это скорее документация, чем реальный вопрос.Кажется, это еще не решено в SO (если я не пропустил его), поэтому здесь идет речь:

Представьте общий класс, содержащий статический член:

class Foo<T> {
    public static int member;
}

новый экземпляр члена для каждого конкретного класса, или существует только один экземпляр для всех классов Foo-типа?

Это можно легко проверить с помощью следующего кода:

Foo<int>.member = 1;
Foo<string>.member = 2;
Console.WriteLine (Foo<int>.member);

Чторезультат и где задокументировано это поведение?

Ответы [ 6 ]

85 голосов
/ 14 июня 2010
Поле

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 вышеупомянутого документа:

Объявление универсального типа само по себе обозначает несвязанный универсальный тип, который используется в качестве «плана» для формирования множества различных типовпутем применения аргументов типа.

14 голосов
/ 14 июня 2010

Проблема здесь на самом деле в том, что «универсальные классы» вообще не являются классами.

Определения универсальных классов - это просто шаблоны для классов, и пока параметры их типов не указаны, они являются лишь частьютекст (или горстка байтов).

Во время выполнения можно указать параметр типа для шаблона, таким образом, приведя его в исполнение и создав класс, теперь полностью определенного типа.Вот почему статические свойства не распространяются на весь шаблон, и поэтому вы не можете приводить значения между List<string> и List<int>.

Это отношение как бы отражает отношение класса-объекта.Так же, как классы не существуют * до тех пор, пока вы не создадите из них объект, общие классы не существуют, пока вы не создадите класс на основе шаблона.

PS Вполне возможно объявить

class Foo<T> {
    public static T Member;
}

Из этого очевидно, что статические члены не могут быть общими, так как T отличается для разных специализаций.

4 голосов
/ 14 июня 2010

Они не являются общими.Не уверен, где это задокументировано, но предупреждение анализа CA1000 ( Не объявлять статические члены для универсальных типов ) предостерегает против этого только из-за риска усложнения кода.

3 голосов
/ 10 сентября 2015

C # реализация дженериков ближе к C ++.В обоих этих языках MyClass<Foo> и MyClass<Bar> не имеют общих статических элементов, но в Java они имеют.В C # и C ++ MyClass<Foo> внутренне создает совершенно новый тип во время компиляции, как если бы дженерики были своего рода макросами.Обычно вы можете увидеть их сгенерированные имена в трассировке стека, например MyClass'1 и MyClass'2.Вот почему они не разделяют статические переменные.В Java дженерики реализованы более простым способом генерации кода компилятором с использованием неуниверсальных типов и добавления приведений типов повсюду.Так что MyClass<Foo> и MyClass<Bar> не генерируют два совершенно новых класса в Java, вместо этого они оба имеют один и тот же класс MyClass внизу, и поэтому они совместно используют статические переменные.

1 голос
/ 14 июня 2010

Они на самом деле не являются общими.Потому что член вообще не принадлежит экземпляру.Статический член класса принадлежит самому классу.Итак, если у вас есть MyClass.Number, он одинаков для всех объектов MyClass.Number, потому что он даже не зависит от объекта.Вы даже можете вызвать или изменить MyClass.Number без какого-либо объекта.

Но поскольку Foo не является тем же классом, что и Foo , эти два числа не являются общими.

Примерпоказать это:

TestClass<string>.Number = 5;
TestClass<int>.Number = 3;

Console.WriteLine(TestClass<string>.Number);  //prints 5
Console.WriteLine(TestClass<int>.Number);     //prints 3
0 голосов
/ 14 июня 2010

ИМО, вам нужно это проверить, но я думаю, что

Foo<int>.member = 1;
Foo<string>.member = 2;
Console.WriteLine (Foo<int>.member);

выведет 1, потому что я думаю, что во время компиляции компилятор создает 1 класс для каждого используемого вами универсального класса (в вашем примере: Foo<int> и Foo<string>).

Но я не уверен на 100% =).

Примечание: я думаю, что это не хороший дизайн и не хорошая практика использовать такие статические атрибуты.

...