对泛型类型参数调用静态方法

我本来希望做这样的事情,但是在 C # 中似乎是非法的:

public Collection MethodThatFetchesSomething<T>()
where T : SomeBaseClass
{
return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}

我得到一个编译时错误:

“ T”是一个“类型参数”,在给定的上下文中无效。

给定一个泛型类型参数,如何调用泛型类上的静态方法?考虑到约束,静态方法必须是可用的。

91920 次浏览

现在不行。你需要一种方法来告诉编译器 T 有这个方法,但是目前还没有办法做到这一点。(许多公司正在推动微软扩大通用约束中可以指定的内容,因此这在未来也许是可能的)。

It sounds like you're trying to use generics to work around the fact that there are no "virtual static methods" in C#.

不幸的是,这样不行。

调用这种方法的唯一方法是通过反射,但是,似乎可以将该功能封装在一个接口中,并使用基于实例的 IoC/Factory/etc 模式。

在这种情况下,您应该直接调用受约束类型上的 static 方法。C # (和 CLR)不支持虚静态方法。所以:

T.StaticMethodOnSomeBaseClassThatReturnsCollection

...can be no different than:

SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection

通过泛型类型参数是不需要的间接操作,因此不受支持。

Here, i post an example that work, it's a workaround

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();
}

您应该能够使用反射来实现这一点,如 给你所述

Due to link being dead, I found the relevant details in the wayback machine:

假设您有一个具有静态泛型方法的类:

class ClassWithGenericStaticMethod
{
public static void PrintName<T>(string prefix) where T : class
{
Console.WriteLine(prefix + " " + typeof(T).FullName);
}
}

如何使用反射调用此方法?

事实证明这非常简单... 这就是如何调用静态泛型的方法 使用反射的方法:

// Grabbing the type that has the static generic method
Type typeofClassWithGenericStaticMethod = typeof(ClassWithGenericStaticMethod);


// Grabbing the specific static method
MethodInfo methodInfo = typeofClassWithGenericStaticMethod.GetMethod("PrintName", System.Reflection.BindingFlags.Static | BindingFlags.Public);


// Binding the method info to generic arguments
Type[] genericArguments = new Type[] { typeof(Program) };
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);


// Simply invoking the method and passing parameters
// The null parameter is the object to call the method from. Since the method is
// static, pass null.
object returnValue = genericMethodInfo.Invoke(null, new object[] { "hello" });

为了详细说明之前的答案,我认为反射更接近于您在这里想要的。我可以给出1001个你应该或不应该做某事的理由,我只是回答你的问题。我认为您应该对泛型参数的类型调用 GetMethod 方法,然后从这里开始。例如,对于一个函数:

public void doSomething<T>() where T : someParent
{
List<T> items=(List<T>)typeof(T).GetMethod("fetchAll").Invoke(null,new object[]{});
//do something with items
}

其中 T 是具有静态方法 fetchAll ()的任何类。

是的,我知道这个过程非常缓慢,如果父类不强制所有子类实现 fetchAll,它可能会崩溃,但是它会回答问题。

我只是想说,有时委托会根据上下文解决这些问题。

如果您需要将静态方法作为某种类型的工厂或初始化方法来调用,那么您可以声明一个委托,并将静态方法传递给相关的泛型工厂或需要这个“带有这个静态方法的泛型类”的任何东西。

例如:

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();
}
}

Unfortunately you can't enforce that the class has the right method, but you can at least compile-time-enforce that the resulting factory method has everything it expects (i.e an initialization method with exactly the right signature). This is better than a run time reflection exception.

这种方法也有一些好处,比如可以重用 init 方法,让它们成为实例方法等等。

You can do what I call a surrogate singleton, I've been using it as a sort of "static inheritance" for a while

interface IFoo<T> where T : IFoo<T>, new()
{
ICollection<T> ReturnsCollection();
}


static class Foo<T> where T : IFoo<T>, new()
{
private static readonly T value = new();
public static ICollection<T> ReturnsCollection() => value.ReturnsCollection();
}


// Use case


public ICollection<T> DoSomething<T>() where T : IFoo<T>, new()
{
return Foo<T>.ReturnsCollection();
}