在表达式中使用 ExpandoObject 而不是原始实体
Using an ExpandoObject instead of the original entity in an expression
我的表达方式如下:
Expression<Func<MyEntity, bool>> exp = x => x.FirstName == "Jonas";
表达式被转移到另一个不具有类型 MyEntity
.
的应用程序
为了能够执行表达式,我正在尝试使用 ExpressionVistor
.
将其中的类型替换为 ExpandoObject
public class ReplaceToExpandoVisitor : ExpressionVisitor
{
ParameterExpression _parameter;
private Type _targetType = typeof(ExpandoObject);
public ReplaceToExpandoVisitor(ParameterExpression p2)
{
_parameter = p2;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return _parameter;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
throw new NotSupportedException();
var memberName = node.Member.Name;
var propBinder = Binder.GetMember(CSharpBinderFlags.None,
memberName,
GetType(),
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
var inner = Visit(node.Expression);
// this is the right way, right?
var exp2 = Expression.Dynamic(propBinder, typeof(object), inner);
// I need to convert it right? Otherwise it will be of type object?
var propGetExpression = Expression.Convert(exp2, node.Type);
return propGetExpression;
}
}
但是,表达式returns执行时为false。所以我想我没有正确访问 expandoobject 中的 "property"。
有人可以解释我做错了什么吗?
我认为您使用活页夹过于复杂了。 ExpandoObject
实现了 IDictionary<string, object>
接口,因此您可以将 x => x.FirstName == "Jonas"
替换为 x => x["FirstName"] == "Jonas"
,这应该更容易。
此外,您必须重写 VisitLambda
,以修改类型参数,否则转换将失败。
示例代码如下:
public class ReplaceToExpandoVisitor<TSource> : ExpressionVisitor
{
private static readonly PropertyInfo ItemProperty = typeof(IDictionary<string, object>).GetProperty("Item");
private readonly ParameterExpression _targetParameter = Expression.Parameter(typeof(ExpandoObject));
protected override Expression VisitLambda<T>(Expression<T> node)
{
var body = this.Visit(node.Body);
var parameters = node.Parameters.Select(this.Visit).Cast<ParameterExpression>();
return Expression.Lambda(body, parameters);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(TSource))
{
return this._targetParameter;
}
return node;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType != MemberTypes.Property)
{
throw new NotSupportedException();
}
string memberName = node.Member.Name;
return Expression.Convert(
Expression.Property(
this.Visit(node.Expression),
ItemProperty,
Expression.Constant(memberName)
),
((PropertyInfo)node.Member).PropertyType
);
}
}
用法:
Expression<Func<MyEntity, bool>> exp = x => x.FirstName == "Jonas";
Expression<Func<ExpandoObject, bool>> exp2 = (Expression<Func<ExpandoObject, bool>>) new ReplaceToExpandoVisitor<MyEntity>().Visit(exp);
dynamic obj = new ExpandoObject();
obj.FirstName = "Jonas";
bool result = exp2.Compile().Invoke(obj);
我的表达方式如下:
Expression<Func<MyEntity, bool>> exp = x => x.FirstName == "Jonas";
表达式被转移到另一个不具有类型 MyEntity
.
为了能够执行表达式,我正在尝试使用 ExpressionVistor
.
ExpandoObject
public class ReplaceToExpandoVisitor : ExpressionVisitor
{
ParameterExpression _parameter;
private Type _targetType = typeof(ExpandoObject);
public ReplaceToExpandoVisitor(ParameterExpression p2)
{
_parameter = p2;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return _parameter;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
throw new NotSupportedException();
var memberName = node.Member.Name;
var propBinder = Binder.GetMember(CSharpBinderFlags.None,
memberName,
GetType(),
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
var inner = Visit(node.Expression);
// this is the right way, right?
var exp2 = Expression.Dynamic(propBinder, typeof(object), inner);
// I need to convert it right? Otherwise it will be of type object?
var propGetExpression = Expression.Convert(exp2, node.Type);
return propGetExpression;
}
}
但是,表达式returns执行时为false。所以我想我没有正确访问 expandoobject 中的 "property"。
有人可以解释我做错了什么吗?
我认为您使用活页夹过于复杂了。 ExpandoObject
实现了 IDictionary<string, object>
接口,因此您可以将 x => x.FirstName == "Jonas"
替换为 x => x["FirstName"] == "Jonas"
,这应该更容易。
此外,您必须重写 VisitLambda
,以修改类型参数,否则转换将失败。
示例代码如下:
public class ReplaceToExpandoVisitor<TSource> : ExpressionVisitor
{
private static readonly PropertyInfo ItemProperty = typeof(IDictionary<string, object>).GetProperty("Item");
private readonly ParameterExpression _targetParameter = Expression.Parameter(typeof(ExpandoObject));
protected override Expression VisitLambda<T>(Expression<T> node)
{
var body = this.Visit(node.Body);
var parameters = node.Parameters.Select(this.Visit).Cast<ParameterExpression>();
return Expression.Lambda(body, parameters);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(TSource))
{
return this._targetParameter;
}
return node;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.MemberType != MemberTypes.Property)
{
throw new NotSupportedException();
}
string memberName = node.Member.Name;
return Expression.Convert(
Expression.Property(
this.Visit(node.Expression),
ItemProperty,
Expression.Constant(memberName)
),
((PropertyInfo)node.Member).PropertyType
);
}
}
用法:
Expression<Func<MyEntity, bool>> exp = x => x.FirstName == "Jonas";
Expression<Func<ExpandoObject, bool>> exp2 = (Expression<Func<ExpandoObject, bool>>) new ReplaceToExpandoVisitor<MyEntity>().Visit(exp);
dynamic obj = new ExpandoObject();
obj.FirstName = "Jonas";
bool result = exp2.Compile().Invoke(obj);