2017-05-12 89 views
0

考慮的方法,象這樣的簽名:檢查表達式包含一個特定的屬性

MyMethod(params Expression<Func<Subscription, object>>[] fields) 

這就是所謂的喜歡:

MyMethod(x=> x.SomeProperty) 

我如何檢查傳遞給MyMethod這體現在哪裏?例如:

MyMethod(Expression<Func<Subscription, object>>[] fields) { 
    //using contains like this doesnt seem to work 
    if(fields.Contains(x=> x.SomeProperty)) {...} 
} 
+3

你的問題是建立在一個不正確的假設。 「表達式」不一定只是屬性訪問操作,它可以是文字值或其他類型的表達,例如, MyMethod(x => 5 + 2)','MyMethod(x => null)'或者作爲另一個表達式的名字傳入的東西:'MyMethod(x => this.SomeDelegate(x).SomeExtensionMethod )?? 123)' – Dai

+0

@戴謝謝。你是否建議使用不同的參數簽名來實現與我的示例類似的方法?注意:這個用例不需要擔心人們在執行'x => 5 + 2''。最終目標僅僅是讓用戶輕鬆指定他們想要以強類型方式指定的對象上的哪些屬性。 –

回答

0

表達式是非常通用的。你可能首先需要篩選是MemberExpression領域:

public static void MyMethod(params Expression<Func<Subscription, object>>[] fields) 
{ 
    var memberExpressions = fields 
     .Where(f => typeof(MemberExpression).IsAssignableFrom(f.Body.GetType())) 
     .Select(f => (MemberExpression)f.Body) 
     .ToList(); 
    if (memberExpressions.Any(ex => 
     ex.Member.MemberType == MemberTypes.Property && 
     ex.Member.Name == "SomeProperty")) 
    { 
     Console.WriteLine("At least one of the fields expressions passed to this function were x => x.SomeProperty"); 
    } 
} 
2

您可以實現一個ExpressionVisitor,並且尋找在表達式樹命名SomeProperty屬性:

internal class Finder : ExpressionVisitor { 
    private readonly string toFind; 
    public Finder(string toFind) { 
     this.toFind = toFind; 
    } 
    public bool IsFound { get; private set; } 
    protected override Expression VisitMember(MemberExpression node) { 
     IsFound |= node.Member.MemberType == MemberTypes.Property && node.Member.Name == toFind; 
     return base.VisitMember(node); 
    } 
} 

使用訪問者如下:

static void MyMethod(params Expression<Func<Program,object>>[] fields) { 
    foreach (var fieldExpr in fields) { 
     var finder = new Finder("Foo"); 
     finder.Visit(fieldExpr); 
     if (finder.IsFound) { 
      Console.WriteLine("Expression {0} references 'Foo'", fieldExpr); 
     } else { 
      Console.WriteLine("Expression {0} does not reference 'Foo'", fieldExpr); 
     } 
    } 
} 

調用這樣

方法
MyMethod(e => e.Foo, e => e.Bar, e => e.Bar != null ? e.Foo : e.Bar); 

產生這樣的輸出:

Expression e => e.Foo references 'Foo' 
Expression e => e.Bar does not reference 'Foo' 
Expression e => IIF((e.Bar != null), e.Foo, e.Bar) references 'Foo' 

Demo.

相關問題