2015-03-03 25 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); 
} 
相关问题