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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/196661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:37:23  来源:igfitidea点击:

Calling a static method on a generic type parameter

c#generics

提问by Remi Despres-Smyth

I was hoping to do something like this, but it appears to be illegal in C#:

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


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

I get a compile-time error: "'T' is a 'type parameter', which is not valid in the given context."

我收到一个编译时错误:“‘T’是一个‘类型参数’,在给定的上下文中无效。”

Given a generic type parameter, how can I call a static method on the generic class? The static method has to be available, given the constraint.

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

采纳答案by JaredPar

In this case you should just call the static method on the constrainted type directly. C# (and the CLR) do not support virtual static methods. So:

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

T.StaticMethodOnSomeBaseClassThatReturnsCollection

...can be no different than:

...可以无异于:

SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection

Going through the generic type parameter is an unneeded indirection and hence not supported.

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

回答by James Curran

As of now, you can't. You need a way of telling the compiler that T has that method, and presently, there's no way to do that. (Many are pushing Microsoft to expand what can be specified in a generic constraint, so maybe this will be possible in the future).

到目前为止,你不能。您需要一种方法来告诉编译器 T 具有该方法,而目前还没有办法做到这一点。(许多人正在推动 Microsoft 扩展可以在通用约束中指定的内容,所以这可能在未来成为可能)。

回答by Brad Wilson

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

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

Unfortunately, that's not gonna work.

不幸的是,这行不通。

回答by Marc Gravell

The only way of calling such a method would be via reflection, However, it sounds like it might be possible to wrap that functionality in an interface and use an instance-based IoC / factory / etc pattern.

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

回答by JaredPar

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

回答by johnc

You should be able to do this using reflection, as is described here

您应该能够使用反射来做到这一点,如here所述

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

由于链接失效,我在回程机中找到了相关细节:

Assume you have a class with a static generic method:

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

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

How can you invoke this method using relection?

It turns out to be very easy… This is how you Invoke a Static Generic Method using Reflection:

如何使用重选来调用此方法?

事实证明这很容易……这就是您使用反射调用静态通用方法的方式:

// 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" });

回答by Joshua Pech

To elaborate on a previous answer, I think reflection is closer to what you want here. I could give 1001 reasons why you should or should not do something, I'll just answer your question as asked. I think you should call the GetMethod method on the type of the generic parameter and go from there. For example, for a function:

为了详细说明以前的答案,我认为反射更接近您在这里想要的。我可以给出 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
}

Where T is any class that has the static method fetchAll().

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

Yes, I'm aware this is horrifically slow and may crash if someParent doesn't force all of its child classes to implement fetchAll but it answers the question as asked.

是的,我知道这非常慢,如果 someParent 不强制其所有子类实现 fetchAll ,它可能会崩溃,但它会按要求回答问题。

回答by Amir Abiri

I just wanted to throw it out there that sometimes delegates solve these problems, depending on context.

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

If you need to call the static method as some kind of a factory or initialization method, then you could declare a delegate and pass the static method to the relevant generic factory or whatever it is that needs this "generic class with this static method".

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

For example:

例如:

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.

不幸的是,您不能强制该类具有正确的方法,但您至少可以在编译时强制生成的工厂方法具有它所期望的一切(即具有完全正确签名的初始化方法)。这比运行时反射异常要好。

This approach also has some benefits, i.e you can reuse init methods, have them be instance methods, etc.

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