c# - parametros - Llamar a un método estático en un parámetro de tipo genérico
metodos estaticos c# (8)
Aquí, publico un ejemplo que funciona, es una solución
public interface eInterface {
void MethodOnSomeBaseClassThatReturnsCollection();
}
public T:SomeBaseClass, eInterface {
public void MethodOnSomeBaseClassThatReturnsCollection()
{ StaticMethodOnSomeBaseClassThatReturnsCollection() }
}
public Collection MethodThatFetchesSomething<T>() where T : SomeBaseClass, eInterface
{
return ((eInterface)(new T()).StaticMethodOnSomeBaseClassThatReturnsCollection();
}
Esperaba hacer algo como esto, pero parece ser ilegal en C #:
public Collection MethodThatFetchesSomething<T>()
where T : SomeBaseClass
{
return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}
Aparece un error en tiempo de compilación: "''T'' es un ''parámetro de tipo'', que no es válido en el contexto dado."
Dado un parámetro de tipo genérico, ¿cómo puedo llamar a un método estático en la clase genérica? El método estático debe estar disponible, dada la restricción.
Deberías poder hacer esto usando la reflexión, como se describe here
En este caso, debe llamar directamente al método estático del tipo restringido. C # (y CLR) no son compatibles con los métodos estáticos virtuales. Asi que:
T.StaticMethodOnSomeBaseClassThatReturnsCollection
... no puede ser diferente de:
SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection
Pasar por el parámetro de tipo genérico es una indirección innecesaria y, por lo tanto, no es compatible.
La única forma de llamar a un método de este tipo sería a través de la reflexión. Sin embargo, parece que sería posible ajustar esa funcionalidad en una interfaz y usar un patrón IoC / factory / etc basado en instancia.
Para elaborar una respuesta anterior, creo que la reflexión está más cerca de lo que quieres aquí. Podría dar 1001 razones por las que debería o no hacer algo, solo responderé a su pregunta como se lo solicite. Creo que deberías llamar al método GetMethod sobre el tipo del parámetro genérico e ir desde allí. Por ejemplo, para una función:
public void doSomething<T>() where T : someParent
{
List<T> items=(List<T>)typeof(T).GetMethod("fetchAll").Invoke(null,new object[]{});
//do something with items
}
Donde T es cualquier clase que tiene el método estático fetchAll ().
Sí, soy consciente de que esto es terriblemente lento y puede fallar si algún padre no fuerza a todas sus clases hijas a implementar fetchAll, sino que responde a la pregunta como se le pidió.
Parece que estás intentando usar genéricos para evitar el hecho de que no hay "métodos estáticos virtuales" en C #.
Desafortunadamente, eso no va a funcionar.
Por ahora, no puedes. Necesita una forma de decirle al compilador que T tiene ese método, y en este momento, no hay forma de hacerlo. (Muchos están presionando a Microsoft para expandir lo que se puede especificar en una restricción genérica, por lo que tal vez esto sea posible en el futuro).
Solo quería arrojarlo allí que a veces los delegados resuelven estos problemas, dependiendo del contexto.
Si necesita llamar al método estático como una especie de fábrica o método de inicialización, puede declarar un delegado y pasar el método estático a la fábrica genérica pertinente o lo que sea que necesite esta "clase genérica con este método estático".
Por ejemplo:
class Factory<TProduct> where TProduct : new()
{
public delegate void ProductInitializationMethod(TProduct newProduct);
private ProductInitializationMethod m_ProductInitializationMethod;
public Factory(ProductInitializationMethod p_ProductInitializationMethod)
{
m_ProductInitializationMethod = p_ProductInitializationMethod;
}
public TProduct CreateProduct()
{
var prod = new TProduct();
m_ProductInitializationMethod(prod);
return prod;
}
}
class ProductA
{
public static void InitializeProduct(ProductA newProduct)
{
// .. Do something with a new ProductA
}
}
class ProductB
{
public static void InitializeProduct(ProductB newProduct)
{
// .. Do something with a new ProductA
}
}
class GenericAndDelegateTest
{
public static void Main()
{
var factoryA = new Factory<ProductA>(ProductA.InitializeProduct);
var factoryB = new Factory<ProductB>(ProductB.InitializeProduct);
ProductA prodA = factoryA.CreateProduct();
ProductB prodB = factoryB.CreateProduct();
}
}
Desafortunadamente no se puede exigir que la clase tenga el método correcto, pero al menos se puede compilar en tiempo real para que el método de fábrica resultante tenga todo lo que se espera (es decir, un método de inicialización con la firma correcta). Esto es mejor que una excepción de reflexión de tiempo de ejecución.
Este enfoque también tiene algunos beneficios, es decir, puede reutilizar los métodos de inicio, tenerlos como métodos de instancia, etc.