Esto es más una documentación que una pregunta real. Esto no parece haberse abordado todavía en SO (a menos que me lo haya perdido), así que aquí va:
Imagina una clase genérica que contiene un miembro estático:
class Foo<T> {
public static int member;
}
¿Existe una nueva instancia del miembro para cada clase específica, o hay una sola instancia para todas las clases de tipo Foo?
Se puede verificar fácilmente mediante un código como este:
Foo<int>.member = 1;
Foo<string>.member = 2;
Console.WriteLine (Foo<int>.member);
¿Cuál es el resultado y dónde se documenta este comportamiento?
T
usado (Foo<int>
yFoo<string>
representan dos clases diferentes, y tendrán una instancia cada una, pero varias intances deFoo<int>
compartirán una sola instancia demember
). Para obtener un ejemplo más detallado, consulte: stackoverflow.com/a/38369256/336648Respuestas:
Un
static
campo se comparte entre todas las instancias del mismo tipo .Foo<int>
yFoo<string>
son dos tipos diferentes. Esto se puede probar con la siguiente línea de código:// this prints "False" Console.WriteLine(typeof(Foo<int>) == typeof(Foo<string>));
En cuanto a dónde está documentado, lo siguiente se encuentra en la sección 1.6.5 Campos de la Especificación del lenguaje C # (para C # 3):
Como se dijo antes;
Foo<int>
yFoo<string>
no son de la misma clase; son dos clases diferentes construidas a partir de la misma clase genérica. Cómo sucede esto se describe en la sección 4.4 del documento mencionado anteriormente:fuente
Foo<int>
yFoo<String>
son tipos diferentes en C #, son del mismo tipo en Java debido a cómo Java maneja los genéricos (borrado de tipos / trucos del compilador).El problema aquí es en realidad el hecho de que las "clases genéricas" no son clases en absoluto.
Las definiciones de clases genéricas son solo plantillas para clases, y hasta que se especifican sus parámetros de tipo, son solo un fragmento de texto (o un puñado de bytes).
En tiempo de ejecución, se puede especificar un parámetro de tipo para la plantilla, dándole vida y creando una clase del tipo, ahora, completamente especificado. Es por eso que las propiedades estáticas no abarcan toda la plantilla, y es por eso que no puede lanzar entre
List<string>
yList<int>
.Esa relación refleja un poco la relación clase-objeto. Al igual que las clases no existen * hasta que crea una instancia de un objeto a partir de ellas, las clases genéricas no existen hasta que crea una clase basada en la plantilla.
PD: Es bastante posible declarar
class Foo<T> { public static T Member; }
A partir de esto, es bastante obvio que los miembros estáticos no se pueden compartir, ya que T es diferente para diferentes especializaciones.
fuente
No se comparten. No estoy seguro de dónde está documentado, pero la advertencia de análisis CA1000 ( No declarar miembros estáticos en tipos genéricos ) advierte contra esto debido al riesgo de complicar el código.
fuente
La implementación de genéricos en C # está más cerca de C ++. En ambos lenguajes
MyClass<Foo>
yMyClass<Bar>
no comparten miembros estáticos, pero sí en Java. En C # y C ++MyClass<Foo>
crea internamente un tipo completamente nuevo en tiempo de compilación como si los genéricos fueran una especie de macros. Por lo general, puede ver sus nombres generados en el seguimiento de la pila, comoMyClass'1
yMyClass'2
. Por eso no comparten variables estáticas. En Java, los genéricos se implementan mediante un método más simple de compilador que genera código utilizando tipos no genéricos y agregando conversiones de tipos por todas partes. Entonces,MyClass<Foo>
yMyClass<Bar>
no genere dos clases completamente nuevas en Java, en cambio, ambas son la misma clase porMyClass
debajo y es por eso que comparten variables estáticas.fuente
Realmente no se comparten. Porque el miembro no pertenece a la instancia en absoluto. Un miembro de clase estática pertenece a la propia clase. Entonces, si tiene MyClass.Number, es el mismo para todos los objetos MyClass.Number porque ni siquiera depende del objeto. Incluso puede llamar o modificar MyClass.Number sin ningún objeto.
Pero como Foo <int> no es de la misma clase que Foo <string>, estos dos números no se comparten.
Un ejemplo para mostrar esto:
TestClass<string>.Number = 5; TestClass<int>.Number = 3; Console.WriteLine(TestClass<string>.Number); //prints 5 Console.WriteLine(TestClass<int>.Number); //prints 3
fuente
En mi opinión, necesitas probarlo, pero creo que
Foo<int>.member = 1; Foo<string>.member = 2; Console.WriteLine (Foo<int>.member);
saldrá
1
porque creo que, durante la compilación, el compilador crea 1 clase para cada clase genérica que usa (en su ejemplo:Foo<int>
yFoo<string>
).Pero no estoy 100% seguro =).
Observación: Creo que no es un buen diseño ni una buena práctica utilizar este tipo de atributos estáticos.
fuente