Reputation: 486
I have a method like this :
public static Expression<Func<T, IEnumerable<byte>>> GetSerializer(Expression<Func<T, int>> expr)
{
return m => BitConverter.GetBytes();
}
T
is a class with different member type : int
, string
, bool
or custom classes.
I would like to know if it is possible in this method to make an expression
where I serialize the int
variable from parameters to byte[]
and return it.
My goal is to execute this code later.
It is only theorical, I don't want to serialize an int, just trying to understand how Expressions
work.
Upvotes: 1
Views: 173
Reputation: 16140
To make expression that invokes other expression, you should build it dynamically. Example:
public static Expression<Func<T, IEnumerable<byte>>> GetSerializer<T>(Expression<Func<T, int>> expr)
{
// Find GetBytes method which accepts int as an argument
var method = typeof(BitConverter).GetMethod("GetBytes", BindingFlags.Static | BindingFlags.Public, null,
CallingConventions.Any, new[] {typeof(int)}, null);
// Input parameter for lambda -> (T p)
var p = Expression.Parameter(typeof(T));
// Body of lambda -> BitConverter.GetBytes(expr(p))
var body = Expression.Call(method, Expression.Invoke(expr, p));
// Build lambda -> (T p) => BitConverter.GetBytes(expr(p))
return Expression.Lambda<Func<T, IEnumerable<byte>>>(body, p);
}
Note that it looks up for GetBytes
method during runtime, so even if method BitConverter.GetBytes(int)
doesn't exist it will compile.
You can go even further and make this method fully generic:
public static Expression<Func<T, IEnumerable<byte>>> GetSerializer<T, T2>(Expression<Func<T, T2>> expr)
where T2 : struct
{
// Find GetBytes method which accepts T2 as an argument
var method = typeof(BitConverter).GetMethod("GetBytes", BindingFlags.Static | BindingFlags.Public, null,
CallingConventions.Any, new[] {typeof(T2)}, null);
// Check if method exists
if (method == null)
{
throw new ArgumentException("Invalid type provided");
}
// Input parameter for lambda -> (T p)
var p = Expression.Parameter(typeof(T));
// Body of lambda -> BitConverter.GetBytes(expr(p))
var body = Expression.Call(method, Expression.Invoke(expr, p));
// Build lambda -> (T p) => BitConverter.GetBytes(expr(p))
return Expression.Lambda<Func<T, IEnumerable<byte>>>(body, p);
}
Upvotes: 1