Generic Method Executed with a runtime type
Solution 1
You can, but it involves reflection, but you can do it.
typeof(ClassExample)
.GetMethod("DoSomething")
.MakeGenericMethod(p.DisplayType)
.Invoke(this, new object[] { p.Name, p.Value });
This will look at the top of the containing class, get the method info, create a generic method with the appropriate type, then you can call Invoke on it.
Solution 2
this.GetType().GetMethod("DoSomething").MakeGenericMethod(p.Value.GetType()).Invoke(this, new object[]{p.Name, p.Value});
Should work.
Solution 3
Generics types cannot be specified at runtime the way you'd like to here.
The simplest options would be to add a non-generic overload of DoSomething
, or simply call DoSomething<object>
and ignore p.DisplayType
. Unless SendToDatabase
depends on the compile-time type of value
(and it probably shouldn't), there should be nothing wrong with giving it an object
.
If you can't do those, you'll have to call DoSomething
using reflection, and you'll take a big performance hit.
Solution 4
First we need to convert p.Value
to the right type, since even if we know the type at compile time we can't pass the string straight to the method...
DoSomething<Int32>( "10" ); // Build error
For simple numeric types and DateTime, we can use
object convertedValue = Convert.ChangeType(p.Value, p.DisplayType);
Now we can use reflection to invoke the required generic method...
typeof(ClassExample)
.GetMethod("DoSomething")
.MakeGenericMethod(p.DisplayType)
.Invoke(this, new object[] { p.Name, convertedValue });
Solution 5
Strictly saying you can use MethodInfo.MakeGenericMethod for this.
But I recommend to change DoSomething to non-generic form instead, since it is not evident whether it really should be generic.
Comments
-
Sarit over 3 years
I have the following code:
public class ClassExample { void DoSomthing<T>(string name, T value) { SendToDatabase(name, value); } public class ParameterType { public readonly string Name; public readonly Type DisplayType; public readonly string Value; public ParameterType(string name, Type type, string value) { if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name"); if (type == null) throw new ArgumentNullException("type"); this.Name = name; this.DisplayType = type; this.Value = value; } } public void GetTypes() { List<ParameterType> l = report.GetParameterTypes(); foreach (ParameterType p in l) { DoSomthing<p.DisplayType>(p.Name, (p.DisplayType)p.Value); } } }
Now, I know I cannot perform DoSomething() is there any other way to use this function?
-
Sarit over 14 yearsI just simplified the program for the explanation. This is actually the most elegant solution, believe it or not. :) thanks!
-
stevemegson over 14 yearsJust one catch, p.Value is a string so the invoke will fail unless p.DisplayType happens to be typeof(string).
-
Andrew Bullock over 14 yearsshame this is the only solution, meh
-
Chris Patterson over 14 yearsWell, I'm thinking that you can use dynamic in 4.0 and it will infer the correct generic argument type, but I haven't had a chance to verify it yet. Not that it is doing anything different under the covers than the above code, but maybe it is.
-
Engineer about 5 yearsAbout brevity: Can does not imply should.