我正在尝试转换c#表达式。这是我正在寻找的示例结果。转换:
Expression<Func<TestObj, bool>> filter = p => p.LastName == "Smith";
到此:
Expression<Func<DynamicItem, bool>> converted = p => p.FieldID == 5 && p.FieldValue == "Smith"
FieldID实际上是通过反映类的属性来获取的,如下面的代码所示。我现在得到的错误是从Convert返回,其中错误是“类型'System.Int32'的表达式不能用于返回类型'System.Boolean'”
我撞墙了,想到也许有人能看到我在这里做错了什么。这是我的代码:
public class MongoReplaceAttribute : Attribute
{
public int FieldID { get; set; }
}
public class TestObj
{
[MongoReplaceAttribute(FieldID = 1)]
public string FirstName { get; set; }
[MongoReplaceAttribute(FieldID = 2)]
public string LastName { get; set; }
}
public class DynamicItem
{
public int FieldID { get; set; }
public string FieldValue { get; set; }
}
class Program
{
static void Main(string[] args)
{
string v = "Smith";
Expression<Func<TestObj, bool>> test = p => p.LastName == v;
var list = MagicFunction(test);
Console.ReadLine();
}
static IEnumerable<DynamicItem> MagicFunction(Expression<Func<TestObj, bool>> filter)
{
List<DynamicItem> rands = new List<DynamicItem>()
{
new DynamicItem
{
FieldID = 1,
FieldValue = "Bob"
},
new DynamicItem
{
FieldID = 2,
FieldValue = "Smith"
},
new DynamicItem
{
FieldID = 1,
FieldValue = "Alice"
},
new DynamicItem
{
FieldID = 2,
FieldValue = "Smith"
}
};
var f2 = Converter<DynamicItem>.Convert(filter);
return rands.AsQueryable<DynamicItem>().Where(f2);
}
}
class Converter<TTo>
{
class ConversionVisitor : ExpressionVisitor
{
private readonly ParameterExpression newParameter;
private readonly ParameterExpression oldParameter;
public ConversionVisitor(ParameterExpression newParameter, ParameterExpression oldParameter)
{
this.newParameter = newParameter;
this.oldParameter = oldParameter;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
return base.VisitLambda<T>(node);
}
protected override Expression VisitBinary(BinaryExpression node)
{
Expression left = this.Visit(node.Left);
Expression right = this.Visit(node.Right);
Expression conversion = this.Visit(node.Conversion);
if (left != node.Left)
{
return base.Visit(left);
}
else if (right != node.Right)
{
var r = base.Visit(right);
return r;
}
else
{
return node;
}
}
protected override Expression VisitParameter(ParameterExpression node)
{
return newParameter;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression != oldParameter)
{
return base.VisitMember(node);
}
var s = node.Member;
var attrReader = s.GetCustomAttributes(typeof(MongoReplaceAttribute), true).Cast<MongoReplaceAttribute>();
//If we are a mongo attribute
if (attrReader != null && attrReader.Count() > 0)
{
var id = attrReader.First().FieldID;
Expression<Func<DynamicItem, bool>> ret = p => p.FieldID == id && p.FieldValue == (string)GetValue(node);
ParameterExpression param = Expression.Parameter(typeof(DynamicItem), "p");
var lambda = Expression.Lambda<Func<DynamicItem, bool>>(ret.Body, param);
return base.Visit(lambda.Body);
}
return base.VisitMember(node);
}
private object GetValue(MemberExpression member)
{
var objectMember = Expression.Convert(member, typeof(object));
var getterLambda = Expression.Lambda<Func<object>>(objectMember);
var getter = getterLambda.Compile();
return getter();
}
}
public static Expression<Func<TTo, TR>> Convert<TFrom, TR>(
Expression<Func<TFrom, TR>> e)
{
var oldParameter = e.Parameters[0];
var newParameter = Expression.Parameter(typeof(TTo), oldParameter.Name);
var converter = new ConversionVisitor(newParameter, oldParameter);
var newBody = converter.Visit(e.Body);
return Expression.Lambda<Func<TTo, TR>>(newBody, newParameter);
}
}
答案 0 :(得分:0)
以下代码中的newBody
似乎未正确创建。 e.Body
为p.LastName == "Smith"
但newBody
为p.FieldID
而非预期p.FieldId==5
。注意缺少的相等比较。
因此,在最后一行中,当您尝试从返回int(p.FieldId)的主体创建Func<DynamicItem, bool>
的Lambda时,它会抛出错误。
这很可能是由于ConversionVisitor中的一些错误。调试您的ConversionVisitor以查看它为什么会创建错误的正文。
public static Expression<Func<TTo, TR>> Convert<TFrom, TR>(
Expression<Func<TFrom, TR>> e)
{
var oldParameter = e.Parameters[0];
var newParameter = Expression.Parameter(typeof(TTo), oldParameter.Name);
var converter = new ConversionVisitor(newParameter, oldParameter);
var newBody = converter.Visit(e.Body);
return Expression.Lambda<Func<TTo, TR>>(newBody, newParameter);
}