簡體   English   中英

C#在運行時使用字符串創建表達式

[英]C# Creating an Expression in runtime with a string

所以,讓我說我有一種方法如下:

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”的名稱
  • “Bar”類的名稱
  • 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方法?

我覺得你不需要動態:

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<targetClassName, bool> ,因此您無法輕松編譯和使用它。

創建內部執行Func<object, bool>轉換的Func<object, bool>更容易。

{
    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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM