对泛型类型参数调用静态方法
本文关键字:静态方法 调用 泛型类型参数 | 更新日期: 2023-09-27 17:47:24
我本来希望做这样的事情,但在C#中似乎是非法的:
public Collection MethodThatFetchesSomething<T>()
where T : SomeBaseClass
{
return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}
我得到一个编译时错误:
"T"是"类型参数",在给定上下文中无效。
给定泛型类型参数,如何在泛型类上调用静态方法?在给定约束的情况下,静态方法必须可用。
在这种情况下,您应该直接调用受约束类型上的静态方法。C#(和CLR)不支持虚拟静态方法。因此:
T.StaticMethodOnSomeBaseClassThatReturnsCollection
可以与没有什么不同
SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection
遍历泛型类型参数是不必要的间接操作,因此不受支持。
为了详细说明前面的答案,我认为这里的反思更接近您想要的。我可以给出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()的类。
是的,我知道这非常慢,如果someParent不强制其所有子类实现fetchAll,但它按要求回答了问题,那么它可能会崩溃。
你可以做我称之为代理单例的事情,我一直把它当作一种"静态继承";
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();
}
调用这样一个方法的唯一方法是通过反射。然而,听起来可能可以将该功能封装在接口中,并使用基于实例的IoC/factory/etc模式。
听起来你正试图使用泛型来解决C#中没有"虚拟静态方法"这一事实。
不幸的是,这行不通。
我只是想说,有时委托会根据上下文解决这些问题。
如果您需要将静态方法调用为某种工厂或初始化方法,那么您可以声明一个委托,并将静态方法传递给相关的泛型工厂或任何需要此"具有此静态方法的泛型类"的工厂。
例如:
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();
}
}
不幸的是,您不能强制类具有正确的方法,但您至少可以在编译时强制生成的工厂方法具有所需的一切(即,具有正确签名的初始化方法)。这比运行时反射异常要好。
这种方法也有一些好处,即您可以重用init方法,将它们作为实例方法等。
您应该能够使用反射来实现这一点,正如这里所描述的
由于链接已失效,我在折返机中发现了相关细节:
假设您有一个具有静态泛型方法的类:
class ClassWithGenericStaticMethod
{
public static void PrintName<T>(string prefix) where T : class
{
Console.WriteLine(prefix + " " + typeof(T).FullName);
}
}
如何使用relation调用此方法?
它变得非常简单…这就是调用静态泛型的方法使用反射的方法:
// 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" });
到目前为止,您还不能。你需要一种方法告诉编译器T有这个方法,而目前还没有这种方法。(许多人正在推动微软扩大通用约束中可以指定的内容,所以也许这在未来是可能的)。
这里,我发布了一个有效的例子,它是一个变通方法
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();
}