2013-05-29 5 views
13

मान लीजिए मैंBinaryExpression से अभिव्यक्ति के लिए <समारोह <T, bool>>

Expression<Func<SomeType, DateTime>> left = x => x.SomeDateProperty; 
Expression<Func<SomeType, DateTime>> right = x => dateTimeConstant; 
var binaryExpression = Expression.GreaterThan(left, right); 
Expression<Func<SomeType, bool>> predicate = 
          x => x.SomeDateProperty> dateTimeConstant; 

1) मैं कैसे कुछ के साथ अंतिम पंक्ति का काम के दाहिने हाथ की जगह ले सकता है की तरह कुछ है कि बजाय binaryExpression का उपयोग करता है? var predicate = x => binaryExpression; काम नहीं करता है।

2) right हमेशा स्थिर रहता है, जरूरी नहीं कि डेटटाइम.अब। क्या यह कुछ सरल Expression प्रकार का हो सकता है? उदाहरण के लिए, यह कुछ प्रकार पर निर्भर नहीं है, यह सिर्फ स्थिर है।

3) अगर मैं एक string रूप GreaterThan है, वहाँ एक रास्ता Expression में एक ही नाम के साथ विधि को यह स्ट्रिंग से प्राप्त करने के लिए है? सामान्य रूप से, यदि तुलना विधि का नाम string के रूप में दिया गया है, तो मैं स्ट्रिंग से वास्तव में विधि को उसी नाम से Expression कक्षा पर कॉल करने के लिए कैसे जा सकता हूं?

यदि यह महत्वपूर्ण है, तो इसे LINQ से Entities के साथ काम करना होगा।

+0

आप ExpressionVisitor वर्ग का उपयोग करके अभिव्यक्ति पेड़ बदल सकते हैं। – Steven

उत्तर

13

1 और 2: आप अभिव्यक्ति पेड़ मैन्युअल रूप से बनाने ऐसा करने की जरूरत है, संकलक मदद नहीं है क्योंकि यह केवल रेडीमेड भाव कि उनकी सम्पूर्णता में कार्य प्रतिनिधित्व का निर्माण कर सकते हैं। जब आप टुकड़े टुकड़े टुकड़े टुकड़े करना चाहते हैं तो यह उपयोगी नहीं है।

var argument = Expression.Parameter(typeof(SomeType)); 
var left = Expression.Property(argument, "SomeDateProperty"); 
var right = Expression.Constant(DateTime.Now); 

var predicate = Expression.Lambda<Func<SomeType, bool>>(
    Expression.GreaterThan(left, right), 
    new[] { argument } 
); 

आप

var param = new SomeType { 
    SomeDateProperty = DateTime.Now.Add(TimeSpan.FromHours(-1)) 
}; 

Console.WriteLine(predicate.Compile()(param)); // "False" 

3 के साथ एक टेस्ट ड्राइव के लिए यह ले जा सकते हैं:

यहाँ एक सरल अभिव्यक्ति आप चाहते हैं का निर्माण करने के तरीका है के बाद से सभी संभावना में के लिए संभव विकल्पों की संख्या आपकी द्विआधारी भविष्यवाणी काफी छोटी होगी, आप इसे एक शब्दकोश के साथ कर सकते हैं:

var wordToExpression = 
    new Dictionary<string, Func<Expression, Expression, BinaryExpression>> 
{ 
    { "GreaterThan", Expression.GreaterThan }, 
    // etc 
}; 

फिर, पहले स्निपेट में Expression.GreaterThan हार्डकोडिंग के बजाय आप wordToExpression["GreaterThan"](left, right) जैसे कुछ करेंगे।

बेशक इसे प्रतिबिंब के साथ मानक तरीका भी किया जा सकता है।

7

जब आप GreaterThan का उपयोग करते हैं, तो आपको निकायों अभिव्यक्ति निर्दिष्ट करने की आवश्यकता है, न कि लैम्ब्डा स्वयं। दुर्भाग्यवश, एक जटिलता है: दो अभिव्यक्तियों में समान नहीं है।

इस विशेष मामले में, आप बस के बारे में इस के साथ दूर हो सकता है, क्योंकि दूसरी अभिव्यक्ति x

तो प्रयोग नहीं करता है; अपने "1" और "2" द्वारा उत्तर दिया जाना चाहिए:

var binaryExpression = Expression.GreaterThan(left.Body, right.Body); 
    var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression, 
     left.Parameters); 

हालांकि, सामान्य स्थिति में इस संभाल करने के लिए, आप अभिव्यक्ति की पर पुनर्लेखन चाहिए, ठीक-अप करने के लिए पैरामीटर:

var binaryExpression = Expression.GreaterThan(left.Body, 
    new SwapVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body)); 
var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression, 
    left.Parameters); 

साथ:

public class SwapVisitor : ExpressionVisitor 
{ 
    private readonly Expression from, to; 
    public SwapVisitor(Expression from, Expression to) 
    { 
     this.from = from; 
     this.to = to; 
    } 
    public override Expression Visit(Expression node) 
    { 
     return node == from ? to : base.Visit(node); 
    } 
} 

के लिए अपने "3"; इसके लिए कुछ भी अंतर्निहित नहीं है; आप प्रतिबिंब का उपयोग कर सकते हैं, हालांकि:

string method = "GreaterThan"; 

var op = typeof(Expression).GetMethod(method, 
    BindingFlags.Public | BindingFlags.Static, 
    null, new[] { typeof(Expression), typeof(Expression) }, null); 

var rightBody = new SwapVisitor(right.Parameters[0], 
    left.Parameters[0]).Visit(right.Body); 
var exp = (Expression)op.Invoke(null, new object[] { left.Body, rightBody }); 

var lambda = Expression.Lambda<Func<SomeType, bool>>(exp, left.Parameters); 
संबंधित मुद्दे