簡體   English   中英

對泛型類型參數調用靜態方法

[英]Calling a static method on a generic type parameter

我希望做這樣的事情,但它在 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 ,它可能會崩潰,但它會按要求回答問題。

調用這種方法的唯一方法是通過反射,但是,聽起來可以將該功能包裝在接口中並使用基於實例的 IoC / 工廠 / 等模式。

聽起來您正在嘗試使用泛型來解決 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 方法,讓它們成為實例方法等。

到目前為止,你不能。 您需要一種方法來告訴編譯器 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();
}

您應該能夠使用反射來做到這一點,如 here所述

由於鏈接失效,我在回程機中找到了相關細節:

假設您有一個帶有靜態泛型方法的類:

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

你可以做我所謂的代理單例,我已經使用它作為一種“靜態繼承”一段時間了

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM