通用问题...从通用类调用静态方法

发布于 2024-09-14 09:38:05 字数 260 浏览 3 评论 0原文

我有一个泛型类:

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

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

是否可以?

谢谢你,

埃里克

I have a generic class:

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

From that generic class, I would like to access a static function from the LinkedItem Class which is a descendant of MyItem class. (thus without creating an instance of the LinkedItem).

Is it possible?

Thank you,

Eric

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

心奴独伤 2024-09-21 09:38:05

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

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

Yes, it is possible, but you have to use reflection by obtaining a MethodInfo from typeof(T).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static) and then calling Invoke on it.

It can be very useful, particularly if using the same technique on a ConstructorInfo rather than a MethodInfo, to create a generic factory that uses parameters in the constructor. It is though one to use sparingly. In particular, there is no way of guaranteeing at compile time that the type in question has a static method of the required signature, so type-safety is gone and such an error won't be caught until run-time.

云裳 2024-09-21 09:38:05

可以通过反思来完成。没有直接的方法可以做到这一点,因为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());
}

It can be done through reflection. There's no straight forward way to do it since C# has no API constraints on static memebers.

I am not sure what is the scenario you're in, but in most cases this is not a recommended solution :)

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

So, for example the next code will print 100:

public void Test()
{
    Console.WriteLine(new MyList<MyItemImpl>().CallStaticMethod());
}
暗藏城府 2024-09-21 09:38:05

不,这不可能直接从类型参数中实现,因为您无法在泛型类型参数上调用静态方法(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);

No this is not possible directly from the type parameter because you cannot invoke static methods on generic type parameters (C# Lang Spec section 4.5).

A type parameter cannot be used in a member access (§7.5.4) or type name (§3.8) to identify a static member or a nested type.

Yes this is possible to achieve via reflection tricks as other people noted. But generally speaking using reflection to solve a simple method invocation scenario is an indication of bad design.

A much better design would be to pass a factory / delegate around which encapsulates the static method in a type safe manner.

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);
闻呓 2024-09-21 09:38:05

这是不可能的。无法对 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();
    }
}

This isn't possible. There's no way to declare a constraint on the LinkedItem parameter that says that it must contain the static method in question.

Possibly the closest you'll get is:

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();
    }
}
酷到爆炸 2024-09-21 09:38:05

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

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

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:同时,当我输入此内容时,其他人似乎建议采用相同的方法;-)

This is, by default, not possible. However, if you know the name of the method you want to invoke, and you are positive that every LinkedItem type will contain this method, you can use reflection to reach your goal. Note: there's often a better way than resolving to reflection for general programming tasks.

The following will always output true for DoSomething. It invokes a static member that's always available (I removed your generic type constraint, as that's not important with static methods).

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: meanwhile, while I typed this, others seem to suggest the same approach ;-)

維他命╮ 2024-09-21 09:38:05

这是完全可能的,尽管不是直接以您所陈述的方式而不经过反思。您可能希望在基类中实现非静态访问方法,并在每个特定的继承类中重写它。

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

This is completely possible though not directly in the way you are stating without maybe reflection. You would want to implement a non-static access method in the baseclass and have it overridden in every specific inheriting class.

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

Then in your class which has the constraint where T : MyItem you would just call T.AccessSomeStaticStuff();

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文