3

我有一个通用类:

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

从那个泛型类中,我想从 LinkedItem 类访问一个静态函数,它是 MyItem 类的后代。(因此无需创建 LinkedItem 的实例)。

可能吗?

谢谢,

埃里克

4

6 回答 6

2

不,这不可能直接从类型参数中进行,因为您不能在泛型类型参数上调用静态方法(C# 语言规范第 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);
于 2010-08-16T17:19:20.030 回答
2

是的,这是可能的,但是您必须通过从中获取 MethodInfotypeof(T).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static)然后调用Invoke它来使用反射。

它非常有用,特别是如果在 ConstructorInfo 而不是 MethodInfo 上使用相同的技术来创建在构造函数中使用参数的通用工厂。它虽然是一个谨慎使用。特别是,在编译时无法保证所讨论的类型具有所需签名的静态方法,因此类型安全性消失了,直到运行时才会捕获此类错误。

于 2010-08-16T17:33:31.327 回答
2

它可以通过反射来完成。由于C#对静态成员没有 API 限制,因此没有直接的方法可以做到这一点。

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

public class MyList<LinkedItem> : List<LinkedItem> 
                                      where LinkedItem : MyItem, new()
{
    public int CallStaticMethod()
    {
        // Getting a static method named "M" from runtime type of LinkedItem 
        var methodInfo = typeof(LinkedItem)
                      .GetMethod("M", BindingFlags.Static | BindingFlags.Public);

        // Invoking the static method, if the actual method will expect arguments
        // they'll be passed in the array instead of empty array
        return (int) methodInfo.Invoke(null, new object[0]);
    }

}

public class MyItem
{
}

class MyItemImpl : MyItem
{
    public MyItemImpl()
    {
    }

    public static int M()
    {
        return 100;
    }
}

因此,例如下一个代码将打印100

public void Test()
{
    Console.WriteLine(new MyList<MyItemImpl>().CallStaticMethod());
}
于 2010-08-16T17:28:19.620 回答
0

这是不可能的。没有办法声明对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();
    }
}
于 2010-08-16T17:20:01.523 回答
0

这是完全可能的,尽管不是直接以您所说的方式进行,而无需反思。您可能希望在基类中实现一个非静态访问方法,并在每个特定的继承类中覆盖它。

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

然后在你的类中具有约束 where T : MyItem 你只需调用 T.AccessSomeStaticStuff();

于 2010-08-16T17:50:01.713 回答
0

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

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

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

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

于 2010-08-16T17:38:18.047 回答