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
(e.g. 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.
Why not specify the type exactly as you would for a non-dynamic type
p.Foo<int>();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With