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

时间:2009-09-22 18:28:22

标签: c# generics dynamic

请考虑以下代码:

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

    static void Main(string[] args) {
        dynamic p = new Program();
        p.Foo();
    }
}

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

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

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

4 个答案:

答案 0 :(得分: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>();
    }
}

以上代码打印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;
    }
}
编辑:帕维尔在评论中提出了一个惊人的想法。您不需要提出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));
    }
}

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

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

答案 1 :(得分:2)

为什么不完全按照非动态类型

指定类型
p.Foo<int>();

答案 2 :(得分:1)

在这种情况下,“p”的类型无关紧要,无论您将其声明为动态还是程序,都会收到此错误。< / p>

错误是无法推断T的类型,因为没有将类型为T的参数传递给该方法,并且该方法不是泛型类的一部分。在这种情况下,编译器无法推断出T是什么类型。

但您应该可以执行以下操作:

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

    static void Main(string[] args) {
        dynamic p = new Program();
        p.Foo<int>();
    }
}

当你调用Foo时,你只需要明确定义T的类型。

答案 3 :(得分:0)

为什么你不能指定Tdynamic

p.Foo<dynamic>();