我希望这样做,但是在C#中似乎是非法的:
public Collection MethodThatFetchesSomething<T>()
where T : SomeBaseClass
{
return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}
我收到一个编译时错误:“'T'是一个'类型参数',在给定的上下文中无效。”
给定通用类型参数,如何在通用类上调用静态方法?给定约束,静态方法必须可用。
我希望这样做,但是在C#中似乎是非法的:
public Collection MethodThatFetchesSomething<T>()
where T : SomeBaseClass
{
return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}
我收到一个编译时错误:“'T'是一个'类型参数',在给定的上下文中无效。”
给定通用类型参数,如何在通用类上调用静态方法?给定约束,静态方法必须可用。
Answers:
在这种情况下,您应该直接在约束类型上调用static方法。C#(和CLR)不支持虚拟静态方法。所以:
T.StaticMethodOnSomeBaseClassThatReturnsCollection
...没有什么不同:
SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection
通过泛型类型参数是不需要的间接寻址,因此不受支持。
return SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection();
工作吗?如果是这样,您可能希望将其添加到您的答案中。谢谢。它为我工作。就我而言,我的班级有一个类型参数,所以我做到了return SomeBaseClass<T>.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却可能会崩溃,但它会按要求回答问题。
调用这种方法的唯一方法是通过反射,但是,听起来可能可以将该功能包装在接口中并使用基于实例的IoC / factory / etc模式。
听起来您正在尝试使用泛型来解决C#中没有“虚拟静态方法”的事实。
不幸的是,那是行不通的。
到目前为止,您还不能。您需要一种方法告诉编译器T具有该方法,而目前尚无办法。(许多人正在推动Microsoft扩展通用约束中可以指定的内容,因此将来可能会实现这一点)。
在这里,我发布了一个可行的示例,这是一种解决方法
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();
}
public T : SomeBaseClass
意思
我只是想把它扔出去,有时代表会根据情况解决这些问题。
如果您需要将静态方法作为某种工厂或初始化方法来调用,则可以声明一个委托并将该静态方法传递给相关的泛型工厂,或者将其传递给需要该“带有该静态方法的泛型类”的对象。
例如:
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);
}
}
如何使用反射调用此方法?
事实证明,这很容易...这是您使用反射调用静态泛型方法的方式:
// 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" });