C# 一般问题。。。从泛型类调用静态方法

C# 一般问题。。。从泛型类调用静态方法,c#,generics,static-members,C#,Generics,Static Members,我有一个通用类: public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new() { } public类MyList:LinkedItem:MyItem,new()所在的列表 { } 从这个泛型类中,我想从LinkedItem类访问一个静态函数,LinkedItem类是MyItem类的后代。(因此无需创建LinkedItem的实例) 可能吗 谢谢, Eric不,这不

我有一个通用类:

public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new()
{
}
public类MyList:LinkedItem:MyItem,new()所在的列表
{
}
从这个泛型类中,我想从LinkedItem类访问一个静态函数,LinkedItem类是MyItem类的后代。(因此无需创建LinkedItem的实例)

可能吗

谢谢,


Eric

不,这不可能直接从类型参数执行,因为您不能对泛型类型参数调用静态方法(C#Lang Spec第4.5节)

不能在成员访问(§7.5.4)或类型名称(§3.8)中使用类型参数来标识静态成员或嵌套类型

是的,正如其他人所指出的,这可以通过反射技巧来实现。但一般来说,使用反射来解决简单的方法调用场景表明设计很糟糕

更好的设计是传递一个工厂/委托,该工厂/委托以类型安全的方式封装静态方法

class MyItem : MyItem {
  static void TheFunction() { ... }
}

public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new()
{
  public MyList(Action theStaticFunction) {
    ...
  }
}

new MyList<MyItem>(MyItem.TheFunction);
类MyItem:MyItem{
函数()的静态无效({…}
}
公共类MyList:LinkedItem:MyItem,new()所在的列表
{
公共MyList(Action theStaticFunction){
...
}
}
新建MyList(MyItem.TheFunction);

这是不可能的。无法在
LinkedItem
参数上声明约束,该约束表示它必须包含所讨论的静态方法

最接近您的可能是:

public class ILinkedItemFactory<T>
{
    void YourMethodGoesHere();
}

public class MyList<LinkedItem, Factory> : List<LinkedItem>
    where Factory : ILinkedItemFactory<LinkedItem>
    where LinkedItem : MyItem, new()
{
    public MyList(Factory factory)
    {
        factory.YourMethodGoesHere();
    }
}
公共类ILinkedItemFactory
{
作废你的方法Goesher();
}
公共类MyList:列表
工厂所在地:ILinkedItemFactory
其中LinkedItem:MyItem,new()
{
公共MyList(工厂)
{
factory.yourmethodgoesher();
}
}

可以通过反射来完成。因为C#对静态Memeber没有API约束,所以没有直接的方法来实现这一点

我不确定您所处的场景是什么,但在大多数情况下,这不是推荐的解决方案:)


是的,这是可能的,但是您必须使用反射,方法是从
typeof(T).GetMethod(“Foo”,BindingFlags.Public | BindingFlags.Static)
获取MethodInfo,然后对其调用
Invoke


它非常有用,尤其是在构造函数信息(而不是MethodInfo)上使用相同的技术来创建使用构造函数中参数的通用工厂时。虽然这是一种节约使用的方法。特别是,无法在编译时保证所讨论的类型具有所需签名的静态方法,因此类型安全性消失,并且在运行时之前不会捕获此类错误。

默认情况下,这是不可能的。但是,如果您知道要调用的方法的名称,并且确定每个
LinkedItem
类型都将包含此方法,则可以使用反射来实现目标。注意:对于一般编程任务,通常有比解决反射更好的方法

对于
DoSomething
,以下内容将始终输出
true
。它调用始终可用的静态成员(我删除了泛型类型约束,因为这对于静态方法并不重要)

公共类MyList:列表
{
公共场所
{
类型t=类型(LinkedItem);
对象o=新对象();
var result=t.InvokeMember(“ReferenceEquals”,
BindingFlags.InvokeMethod|
BindingFlags.Public|
BindingFlags.Static,
无效的
null,新[]{o,o});
返回值(结果为bool?).Value;
}
}
//可以这样称呼:
MyList ml=新的MyList();
bool value=ml.DoSomething();//真的

PS:与此同时,当我输入这个时,其他人似乎建议使用相同的方法;-)

这是完全可能的,尽管不是直接以你所说的方式进行的,也可能没有思考。您可能希望在基类中实现一个非静态访问方法,并在每个特定的继承类中重写它

public class MyItem
{
    public static void DoSomeStaticStuff() { //DoSomeStaticStuff for MyItem }
    public virtual void AccessSomeStaticStuff() { MyItem.DoSomeStaticStuff(); }
}

public class SomeItem : MyItem
{
    public static void DoSomeStaticStuff() { //DoSomeStaticStuff for SomeItem }
    public override void AccessSomeStaticStuff() { SomeItem.DoSomeStaticStuff(); }
}

然后在约束为T:MyItem的类中,只需调用T.AccessSomeStaticStuff()

静态方法不能是虚拟的,这将无法编译。您会说,“不,这是不可能的”。有三个答案证明这是可能的,以及如何做到这一点。你是如何反对否决票的,你的答案没有误导性?@Jon,即使面对其他答案,我的答案也是正确的。使用反射不是对泛型类型参数调用方法,而是对泛型类型参数的类型调用方法。这两种情况之间有很大的区别。+1我不知道你为什么会被否决,或者被谁否决,但我又一次把它弄平了:)
public void Test()
{
    Console.WriteLine(new MyList<MyItemImpl>().CallStaticMethod());
}
public class MyList<LinkedItem> : List<LinkedItem>
{
    public bool DoSomething()
    {
        Type t = typeof(LinkedItem);
        object o = new Object();
        var result = t.InvokeMember("ReferenceEquals",
            BindingFlags.InvokeMethod |
            BindingFlags.Public |
            BindingFlags.Static,
            null,
            null, new[] { o, o });

        return (result as bool?).Value;
    }
}

// call it like this:
MyList<string> ml = new MyList<string>();
bool value = ml.DoSomething();   // true
public class MyItem
{
    public static void DoSomeStaticStuff() { //DoSomeStaticStuff for MyItem }
    public virtual void AccessSomeStaticStuff() { MyItem.DoSomeStaticStuff(); }
}

public class SomeItem : MyItem
{
    public static void DoSomeStaticStuff() { //DoSomeStaticStuff for SomeItem }
    public override void AccessSomeStaticStuff() { SomeItem.DoSomeStaticStuff(); }
}