使用动态变量时可以指定泛型参数吗?

Dav*_*bbo 4 c# generics dynamic

请考虑以下代码:

class Program {
    void Foo<T>() { }

    static void Main(string[] args) {
        dynamic p = new Program();
        p.Foo();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,对p.Foo()的调用无效,因为动态绑定器无法知道要用于T的类型.具体的失败是:

" 无法从用法中推断出方法'ConsoleApplication1.Program.Foo()'的类型参数.请尝试明确指定类型参数. "

现在我的问题是:有没有办法指定泛型类型,或者这种方法是不是可以使用'dynamic'来调用?

Jon*_*eet 14

正如Jared所说,您可以像在静态调用中一样在代码中指定它:

using System;

class Program {
    void Foo<T>() {
        Console.WriteLine(typeof(T));
    }

    static void Main(string[] args) {
        dynamic p = new Program();
        p.Foo<string>();
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码打印出来System.String.

现在,如果你只是T执行时知道,那就稍微困难了.如果你有一个实例,你可以一起使用动态类型和类型推断:

using System;

class Program {
    void Foo<T>() {
        Console.WriteLine(typeof(T));
    }

    static void Main(string[] args) {
        dynamic p = new Program();
        dynamic v = GetRandomInstance();

        // Now to call p.Foo<T> where T is the type of v's value...
        Dummy(v, p);
    }

    static void Dummy<T>(T t, Program p) {
        p.Foo<T>();
    }

    static object GetRandomInstance() {
        return DateTime.Now.Hour > 10 ? "hello" : (object) 10;
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:帕维尔在评论中提出了一个惊人的想法.您不需要提供一个实例T,只需一个数组.这意味着您甚至可以使用通常无法获取实例的类型参数T(例如,由于私有构造函数):

using System;

class PrivateConstructor {
    private PrivateConstructor() {}
}

class Program {
    static void Foo<T>() {
        Console.WriteLine(typeof(T));
    }

    static void CallFooProxy<T>(T[] array) {
        Foo<T>();
    }

    static void CallFoo(Type t) {
        dynamic array = Array.CreateInstance(t, 0);
        CallFooProxy(array);
    }

    static void Main(string[] args) {
        CallFoo(typeof(PrivateConstructor));
    }
}
Run Code Online (Sandbox Code Playgroud)

在有人要求之前 - 不,这不会让你Foo<Enumerable>动态调用- 你仍然不能使用静态类作为类型参数,即使你试图将尝试延迟到执行时间:)

如果由于某种原因所有这些都失败了,它会恢复正常的反射...获取方法信息,调用MakeGenericMethod并调用它.

  • 如果你使`Dummy <T>`使用类型为`T []`而不是普通`T`的参数用于演绎目的(它应该仍然有效),你可以使用`Array.CreateInstance(runtimeType,0)`来无论是否存在类型为"T"的可访问默认构造函数,都会创建一个虚拟零长度数组. (5认同)
  • 多德.油滑. - (3认同)
  • 那么你们*实施了*那件事.不知怎的,只是*使用*它相形见绌:) (2认同)
  • 请注意,Reflection不会涵盖`dynamic`所做的所有场景(例如,考虑如果接收器是Python对象会发生什么). (2认同)