c# - metodos - ¿Por qué no puedo heredar clases estáticas?
metodos estaticos c# (11)
Tengo varias clases que realmente no necesitan ningún estado. Desde el punto de vista organizativo, me gustaría ponerlos en jerarquía.
Pero parece que no puedo declarar herencia para clases estáticas.
Algo como eso:
public static class Base
{
}
public static class Inherited : Base
{
}
no trabajará.
¿Por qué los diseñadores de la lengua han cerrado esa posibilidad?
Aunque puede acceder a miembros estáticos "heredados" a través del nombre de clases heredado, los miembros estáticos no se heredan realmente. Esto es en parte por qué no pueden ser virtuales o abstractos y no pueden ser anulados. En su ejemplo, si declaró un Método Base. (Método), el compilador asignará una llamada a Inherited.Method () nuevamente a Base.Method () de todos modos. También podrías llamar a Base.Method () explícitamente. Puedes escribir una pequeña prueba y ver el resultado con Reflector.
Entonces ... si no puede heredar miembros estáticos, y si las clases estáticas pueden contener solo miembros estáticos, ¿para qué serviría heredar una clase estática?
Cita de here :
Esto es en realidad por diseño. Parece que no hay una buena razón para heredar una clase estática. Tiene miembros públicos estáticos a los que siempre se puede acceder a través del propio nombre de clase. Las únicas razones que he visto para heredar cosas estáticas han sido malas, como guardar un par de caracteres de la escritura.
Puede haber una razón para considerar mecanismos para llevar a los miembros estáticos directamente al alcance (y de hecho lo consideraremos después del ciclo del producto Orcas), pero la herencia de clase estática no es el camino a seguir: es el mecanismo incorrecto de usar, y funciona solo para miembros estáticos que residen en una clase estática.
(Mads Torgersen, C # Language PM)
Otras opiniones de channel9
La herencia en .NET solo funciona en la base de instancia. Los métodos estáticos se definen en el nivel de tipo y no en el nivel de instancia. Es por eso que la anulación no funciona con métodos / propiedades / eventos estáticos ...
Los métodos estáticos solo se guardan una vez en la memoria. No hay una tabla virtual, etc. que se crea para ellos.
Si invoca un método de instancia en .NET, siempre le asigna la instancia actual. Esto está oculto por el tiempo de ejecución de .NET, pero sucede. Cada método de instancia tiene como primer argumento un puntero (referencia) al objeto en el que se ejecuta el método. Esto no ocurre con los métodos estáticos (como se definen en el nivel de tipo). ¿Cómo debe el compilador decidir seleccionar el método a invocar?
(littleguru)
Y como una idea valiosa, littleguru tiene una "solución" parcial para este problema: el patrón Singleton .
Cuando creamos una clase estática que contiene solo los miembros estáticos y un constructor privado. La única razón es que el constructor estático impide que se cree una instancia de la clase para que no podamos heredar una clase estática. La única forma de acceder al miembro de clase estática utilizando el propio nombre de clase. Tratar de heredar una clase estática no es una buena idea.
Hmmm ... ¿sería muy diferente si tuvieras clases no estáticas llenas de métodos estáticos ...?
La razón principal por la que no puede heredar una clase estática es que son abstractos y están sellados (esto también evita que se cree cualquier instancia de ellos).
Así que esto:
static class Foo { }
compila a esta IL:
.class private abstract auto ansi sealed beforefieldinit Foo
extends [mscorlib]System.Object
{
}
Las clases estáticas y los miembros de la clase se utilizan para crear datos y funciones a las que se puede acceder sin crear una instancia de la clase. Los miembros de la clase estática se pueden usar para separar datos y comportamientos que son independientes de cualquier identidad de objeto: los datos y las funciones no cambian, independientemente de lo que suceda con el objeto. Las clases estáticas se pueden usar cuando no hay datos o comportamiento en la clase que depende de la identidad del objeto.
Una clase se puede declarar estática, lo que indica que solo contiene miembros estáticos. No es posible usar la nueva palabra clave para crear instancias de una clase estática. Las clases estáticas son cargadas automáticamente por el tiempo de ejecución de lenguaje común (CLR) de .NET Framework cuando se carga el programa o el espacio de nombres que contiene la clase.
Use una clase estática para contener métodos que no estén asociados con un objeto en particular. Por ejemplo, es un requisito común crear un conjunto de métodos que no actúan sobre los datos de la instancia y no están asociados a un objeto específico en su código. Podrías usar una clase estática para mantener esos métodos.
Las siguientes son las principales características de una clase estática:
Sólo contienen miembros estáticos.
No pueden ser instanciados.
Están sellados.
No pueden contener constructores de instancias (Guía de programación de C #).
Por lo tanto, crear una clase estática es básicamente lo mismo que crear una clase que contenga solo miembros estáticos y un constructor privado. Un constructor privado evita que la clase sea instanciada.
La ventaja de usar una clase estática es que el compilador puede verificar que ningún miembro de la instancia se agregue accidentalmente. El compilador garantizará que no se puedan crear instancias de esta clase.
Las clases estáticas están selladas y, por lo tanto, no se pueden heredar. No pueden heredar de ninguna clase excepto Objeto. Las clases estáticas no pueden contener un constructor de instancia; Sin embargo, pueden tener un constructor estático. Para obtener más información, consulte Constructores estáticos (Guía de programación de C #).
Lo que quiere lograr usando la jerarquía de clases puede lograrse simplemente a través del espacio de nombres. Por lo tanto, los lenguajes que admiten los papeles de nombre (como C #) no tendrán ningún uso para implementar la jerarquía de clases de clases estáticas. Dado que no puede crear una instancia de ninguna de las clases, todo lo que necesita es una organización jerárquica de definiciones de clase que puede obtener mediante el uso de espacios de nombres.
Piénselo de esta manera: accede a miembros estáticos a través del nombre de tipo, como este:
MyStaticType.MyStaticMember();
Si usted heredara de esa clase, tendría que acceder a ella a través del nuevo nombre de tipo:
MyNewType.MyStaticMember();
Por lo tanto, el nuevo elemento no guarda ninguna relación con el original cuando se utiliza en el código. No habría manera de aprovechar alguna relación de herencia para cosas como el polimorfismo.
Quizás esté pensando que solo quiere ampliar algunos de los elementos de la clase original. En ese caso, no hay nada que le impida utilizar un miembro del original en un tipo completamente nuevo.
Quizás desee agregar métodos a un tipo estático existente. Puede hacerlo ya a través de métodos de extensión.
Quizás desee poder pasar un Type
estático a una función en tiempo de ejecución y llamar a un método de ese tipo, sin saber exactamente qué hace el método. En ese caso, puede utilizar una interfaz.
Entonces, al final, realmente no se gana nada al heredar clases estáticas.
Puede usar la composición en su lugar ... esto le permitirá acceder a objetos de clase desde el tipo estático. Pero todavía no puede implementar interfaces o clases abstractas
Puedes hacer algo que se verá como herencia estática.
Aquí está el truco:
public abstract class StaticBase<TSuccessor>
where TSuccessor : StaticBase<TSuccessor>, new()
{
protected static readonly TSuccessor Instance = new TSuccessor();
}
Entonces puedes hacer esto:
public class Base : StaticBase<Base>
{
public Base()
{
}
public void MethodA()
{
}
}
public class Inherited : Base
{
private Inherited()
{
}
public new static void MethodA()
{
Instance.MethodA();
}
}
La clase Inherited
no es estática en sí misma, pero no permitimos crearla. En realidad, ha heredado el constructor estático que construye la Base
, y todas las propiedades y métodos de la Base
disponibles como estáticos. Ahora lo único que queda por hacer es hacer envoltorios estáticos para cada método y propiedad que necesite exponer a su contexto estático.
Existen desventajas, como la necesidad de creación manual de métodos de envoltura estática y new
palabras clave. Pero este enfoque ayuda a apoyar algo que es realmente similar a la herencia estática.
PS Usamos esto para crear consultas compiladas, y esto en realidad se puede reemplazar con ConcurrentDictionary, pero un campo estático de solo lectura con su seguridad de subprocesos fue lo suficientemente bueno.
Una solución alternativa que puede hacer es no usar clases estáticas sino ocultar el constructor para que las clases miembros estáticos sean lo único accesible fuera de la clase. El resultado es una clase "estática" heredable esencialmente:
public class TestClass<T>
{
protected TestClass()
{ }
public static T Add(T x, T y)
{
return (dynamic)x + (dynamic)y;
}
}
public class TestClass : TestClass<double>
{
// Inherited classes will also need to have protected constructors to prevent people from creating instances of them.
protected TestClass()
{ }
}
TestClass.Add(3.0, 4.0)
TestClass<int>.Add(3, 4)
// Creating a class instance is not allowed because the constructors are inaccessible.
// new TestClass();
// new TestClass<int>();
Desafortunadamente, debido a la limitación de lenguaje "por diseño" no podemos hacer:
public static class TestClass<T>
{
public static T Add(T x, T y)
{
return (dynamic)x + (dynamic)y;
}
}
public static class TestClass : TestClass<double>
{
}