如何在表达式树中创建需要实现多个接口的参数
本文关键字:实现 接口 参数 表达式 创建 | 更新日期: 2023-09-27 18:06:40
我想创建参数(ParameterExpression类的实例),它应该实现多个接口(让它们是IComparable, IFormattable),像这样:
//TypeWithIComparableIFormattable composite_type = ...;
ParameterExpression parameter = Parameter(composite_type, "composite_param");
// Usage specific methods of composite param from implemented interfaces
尽管变量/参数可以是不同类型的实例,但您不能像这样声明它:
IComparable, IFormattable obj;
要进行多接口实现检查,您可以:
从
IComparable
和IFormattable
继承你自己的接口,比如IComparableAndFormattable
。但是这种方法要求参数的类型必须实现接口。执行运行时检查。这是冗长的,但保持了代码的灵活性:
使用Expression.TypeAs()
方法将参数转换为所需的类型。
var param = Expression.Parameter(typeof(object), "o");
// IComparable comparable;
var comparableDeclare = Expression.Parameter(typeof(IComparable), "comparable");
// comparable = o as IComparable;
var comparableAssign = Expression.Assign(comparableDeclare, Expression.TypeAs(param, typeof(IComparable)));
// if (comparable == (IComparable)null)
// {
// throw new ArgumentException("The parameter must be a instance of IComparable.", nameof(o));
// }
var comparableCheck = Expression.IfThen(Expression.Equal(comparableDeclare, Expression.Constant(null, typeof(IComparable))),
ThrowNotTypeOf(typeof(IComparable), param.Name));
var formattableDeclare = Expression.Parameter(typeof(IFormattable), "formattable");
// formattable = o as IFormattable;
var formattableAssign = Expression.Assign(formattableDeclare, Expression.TypeAs(param, typeof(IFormattable)));
// if (formattable == (IFormattable)null)
// {
// throw new ArgumentException("The parameter must be a instance of IFormattable.", nameof(o));
// }
var formattableCheck = Expression.IfThen(
Expression.Equal(formattableDeclare, Expression.Constant(null, typeof(IFormattable))),
ThrowNotTypeOf(typeof(IFormattable), param.Name));
var block = Expression.Block(
new [] {
comparableDeclare, formattableDeclare
}, // local variables
comparableAssign, comparableCheck, formattableAssign, formattableCheck);
foreach (var exp in block.Expressions)
{
Console.WriteLine(exp);
}
// Compile the expression tree
var method = Expression.Lambda<Action<object>>(block, param).Compile();
method.Invoke(new ComparableFormattable());
其中ThrowNotTypeOf
是生成throw new ArgumentException
语句的辅助方法:
private static Expression ThrowNotTypeOf(Type type, string paramName)
{
var ctor = typeof(ArgumentException).GetConstructor(new[] { typeof(string), typeof(string) });
Debug.Assert(ctor != null);
var messageArg = Expression.Constant($"The parameter must be an instance of '{type.Name}'.");
var paramArg = Expression.Constant(paramName);
return Expression.Throw(Expression.New(ctor, messageArg, paramArg));
}