【问题标题】:C# Creating an Expression in runtime with a stringC# 在运行时使用字符串创建表达式
【发布时间】:2015-03-03 09:01:57
【问题描述】:

假设我有以下方式的方法:

public T Get<T, U>(Expression<Func<T, U>> expr) {
    // use the expression to retrieve cool stuff.
}

现在我想只用字符串值调用这个方法。也就是说,我需要在运行时编译一个表达式。

所以,假设我有一个类 Foo:

public class Foo {
    public string Name { get; set; }
}

然后有另一个类Bar:

public class Bar {
    public string AnotherName { get; set; }
}

现在我想编译一个如下所示的表达式:

Foo foo = new Foo { Name = "AName" };
Expression<Func<Bar, string>> expr = p => p.AnotherName == foo.Name;

但是,我在运行时获得的唯一信息是:

  • “AnotherName”属性的名称
  • “酒吧”类的名称
  • Foo 中属性“Name”的值
  • “Foo”类的名称

所以,经过一番潜伏后,我发现有一个 System.Linq.Dynamic 库,我可以在其中编译字符串的 expr:

@"Bar.AnotherName == AName";

例子:

var sourceValue = "AName";
var targetClassName = "Bar";
var targetPropertyName = "AnotherName";

var expr = string.Format("{0}.{1} == {2}", 
    targetClassName, targetPropertyName, sourceValue);

var p = Expression.Parameter(typeof(Bar), "Target");
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, expr);
var lambda = e.Compile();

但是,这只会导致 lambda 表达式的委托。

我现在的问题是,真的可以通过像这样在运行时创建表达式来调用 Get 方法吗?

【问题讨论】:

  • 搜索CSharpCodeProvider。也许矫枉过正,但它会解决你的问题。

标签: c# linq runtime expression


【解决方案1】:

我认为你不需要动态:

var sourceValue = "AName";

// You will need the namespace of Bar here!
var namespaceTargetClassName = "ExpressionProblem";
var targetClassName = "Bar";
var targetPropertyName = "AnotherName";

{
    var targetType = Type.GetType(namespaceTargetClassName + "." + targetClassName);
    var p = Expression.Parameter(targetType, "Target");
    var pr = Expression.PropertyOrField(p, targetPropertyName);
    var e = Expression.Equal(pr, Expression.Constant(sourceValue));
    var lambda = Expression.Lambda(e, p); // It would be an Expression<Func<Bar, bool>>
}

请注意,这第一个解决方案有一个问题:您生成的委托类型是Func&lt;targetClassName, bool&gt;,因此您无法轻松编译和使用它。

创建一个在内部执行转换的Func&lt;object, bool&gt; 更容易。

{
    var targetType = Type.GetType(namespaceTargetClassName + "." + targetClassName);
    var p = Expression.Parameter(typeof(object), "Target");

    // I'm using the as operator here, if you prefer a "strong" 
    // cast (the cast operator that throws if the object is of
    // invalid type), use Expression.Convert with the same syntax 
    var pcasted = Expression.TypeAs(p, targetType); 
    var pr = Expression.PropertyOrField(pcasted, targetPropertyName);
    var e = Expression.Equal(pr, Expression.Constant(sourceValue));
    var lambda = Expression.Lambda<Func<object, bool>>(e, p);

    Func<object, bool> func = lambda.Compile();

    Bar obj = new Bar { AnotherName = "AName" };
    bool res = func(obj);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多