简体   繁体   中英

Can generic parameters be specified when using dynamic variables?

Consider the following code:

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

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

Note surprisingly, the call to p.Foo() is not valid because the dynamic binder has no way of knowing what type to use for T. The specific failure is:

" The type arguments for method 'ConsoleApplication1.Program.Foo()' cannot be inferred from the usage. Try specifying the type arguments explicitly. "

Now my question is: is there a way to specify the generic type, or is such method simply not callable using 'dynamic'?

As Jared says, you can specify it in code just as you would for a static call:

using System;

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

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

The above code prints System.String .

Now if you only know T at execution time, it's slightly harder. If you have an instance of it though, you could use dynamic typing and type inference together:

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

EDIT: Pavel came up with an amazing idea in the comments. You don't need to come up with an instance of T , just an array. This means you can even use type arguments where you wouldn't normally be able to get an instance of T (eg due to a private constructor):

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

Before anyone asks - no, this doesn't let you call Foo<Enumerable> dynamically - you still can't use a static class as a type argument, even if you try to delay the attempt until execution time :)

If all of that fails for some reason, it's back to reflection as normal... get the method info, call MakeGenericMethod and invoke it.

为什么不像非动态类型那样完全指定类型

p.Foo<int>();

In this case, it doesn't matter what type "p" is, whether you declare it as dynamic or as Program , you will receive this error.

The error is saying that the type of T cannot be inferred because there are no parameters of type T being passed to the method, and the method isn't part of a generic class. In this case, there's no way for the compiler to infer what type T is.

You should be able to do the following, though:

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

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

You just need to explicitly define the type of T when you call Foo.

为什么你不能指定Tdynamic

p.Foo<dynamic>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM