This is something that I solved using reflection, but would like to see how to do it using expression trees.
I have a generic function:
private void DoSomeThing<T>( param object[] args ) {
// Some work is done here.
}
that I need to call from else where in my class. Now, normally, this would be be simple:
DoSomeThing<int>( blah );
but only if I know, at design time that I am working with an int
. When I do not know the type until runtime is where I need the help. Like I said, I know how to do it via reflection, but I would like to do it via expression trees, as my (very limited) understanding is that I can do so.
Any suggestions or points to sites where I can get this understanding, preferably with sample code?
Yes, it can be done via expression trees. The advantage is that you get a delegate so repeated calls will be far faster than doing MethodInfo.Invoke()
over and over again. The dynamic
keyword can do this also.
Example:
What type would you like to use?
decimal
Selected type 'System.Decimal'
Input Value:
5.47
<<<USING object>>>
The object has static type 'System.Object', dynamic type 'System.Decimal', and value '5.47'
<<<USING dynamic>>>
The object has static type 'System.Decimal', dynamic type 'System.Decimal', and value '5.47'
<<<USING reflection>>>
The object has static type 'System.Decimal', dynamic type 'System.Decimal', and value '5.47'
<<<USING expression tree>>>
The object has static type 'System.Decimal', dynamic type 'System.Decimal', and value '5.47'
Code:
using System;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace SO2433436
{
class Program
{
static void LogObject<T>(T t)
{
Console.WriteLine("The object has static type '" + typeof(T).FullName + "', dynamic type '" + t.GetType() + "', and value '" + t.ToString() + "'");
}
static void Main(string[] args)
{
Console.WriteLine("What type would you like to use?");
string typeName = Console.ReadLine();
Type userType;
switch (typeName)
{
case "byte": userType = typeof(byte); break;
case "sbyte": userType = typeof(sbyte); break;
case "ushort": userType = typeof(ushort); break;
case "short": userType = typeof(short); break;
case "uint": userType = typeof(uint); break;
case "int": userType = typeof(int); break;
case "string": userType = typeof(string); break;
case "decimal": userType = typeof(decimal); break;
default:
userType = Type.GetType(typeName);
break;
}
Console.WriteLine("Selected type '" + userType.ToString() + "'");
Console.WriteLine("Input Value:");
string val = Console.ReadLine();
object o = TypeDescriptor.GetConverter(userType).ConvertFrom(val);
Console.WriteLine("<<<USING object>>>");
LogObject(o);
Console.WriteLine("<<<USING dynamic>>>");
LogObject((dynamic)o);
Console.WriteLine("<<<USING reflection>>>");
Action<object> f = LogObject<object>;
MethodInfo logger = f.Method.GetGenericMethodDefinition().MakeGenericMethod(userType);
logger.Invoke(null, new[] { o });
Console.WriteLine("<<<USING expression tree>>>");
var p = new[] { Expression.Parameter(typeof(object)) };
Expression<Action<object>> e =
Expression.Lambda<Action<object>>(
Expression.Call(null,
logger,
Expression.Convert(p[0], userType)
)
, p);
Action<object> a = e.Compile();
a(o);
}
}
}
MethodInfo.MakeGenericMethod
Then just create a delegate and call it. (not in an expression, of course ;p)
Update:
Generally, I prefer to use generic types for this, Activator.CreateInstance
just requires less work. All depends on your situation though.
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