在泛型类型参数上调用静态方法

时间:2008-10-13 03:49:43

标签: c# generics

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


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

我收到编译时错误:“'T'是'type parameter',在给定的上下文中无效。”

给定泛型类型参数,如何在泛型类上调用静态方法?在给定约束的情况下,静态方法必须可用。

9 个答案:

答案 0 :(得分:52)

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

T.StaticMethodOnSomeBaseClassThatReturnsCollection

......可能与:

无异
SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection

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

答案 1 :(得分:25)

要详细说明以前的答案,我认为反思更接近你想要的。我可以给出你应该或不应该做某事的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,它可能会崩溃,但它会回答问题。

答案 2 :(得分:7)

调用这种方法的唯一方法是通过反射,但是,听起来可能将该功能包装在接口中并使用基于实例的IoC / factory / etc模式。

答案 3 :(得分:5)

听起来你正在尝试使用泛型来解决C#中没有“虚拟静态方法”这一事实。

不幸的是,那不会起作用。

答案 4 :(得分:2)

截至目前,你不能。你需要一种告诉编译器T有这种方法的方法,现在,没有办法做到这一点。 (许多人正在推动微软扩展通用约束中可以指定的内容,因此将来可能会这样做)。

答案 5 :(得分:2)

在这里,我发布一个有效的例子,这是一个解决方法

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

答案 6 :(得分:2)

我只是想把它扔出去,有时代表会根据上下文解决这些问题。

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

例如:

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方法,让它们成为实例方法等等。

答案 7 :(得分:1)

您应该能够使用反射执行此操作,如here

所述

答案 8 :(得分:0)

你可以做我所谓的代理单例,我一直将它用作一种“静态继承”

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