2015-03-03 63 views
3

所以我們可以說,我有以下方式中的一種方法:C#創建在運行時表達的一個字符串

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」

所以,一些潛伏之後我發現有一個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方法?

+0

搜索'CSharpCodeProvider'。也許矯枉過正,但它會解決你的問題。 – Fendy 2015-03-03 09:17:58

回答

2

我不認爲你需要動態:

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>更容易。

{ 
    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); 
} 
相關問題