2011-07-20 20 views
10

से एक्सेस करना इंडेक्सर मैं एक छानने समारोह पर काम कर रहा हूँ। फिल्टर उपयोगकर्ता द्वारा एक अभिव्यक्ति वृक्ष का निर्माण होगा। फ़िल्टरिंग के लिए उपयोगकर्ता लगभग 30 फ़ील्ड का उपयोग कर सकता है। मुझे लगता है कि इंडेक्सर के साथ ऑब्जेक्ट मॉडल बनाने और एनम प्रकार के सूचकांक द्वारा आवश्यक मानों तक पहुंचने का सबसे अच्छा तरीका है।अभिव्यक्ति पेड़

enum Field 
{ 
    Name, 
    Date, 
} 

class ObjectModel 
{ 
    object this[Field Key] 
    { 
     get 
     { 
      //... 
      return xx; 
     } 
    } 
} 

मैं पूछने के लिए कि कैसे मैं एक अभिव्यक्ति पेड़ से एक इंडेक्सर उपयोग कर सकते हैं करना चाहते हैं:

इस उदाहरण देखें।

उत्तर

15

इंडेक्सर एक सरल संपत्ति, सामान्य रूप से Item कहा जाता है। इसका मतलब है, आप इसके नाम का उपयोग करके किसी अन्य संपत्ति की तरह इंडेक्सर तक पहुंच सकते हैं।

इंडेक्सर गुण का नाम IndexerName attribute के माध्यम से वर्ग के implementor द्वारा बदला जा सकता।

मज़बूती से इंडेक्सर संपत्ति का वास्तविक नाम पाने के लिए आपको वर्ग पर विचार करने और DefaultMember attribute प्राप्त करने के लिए किया है।
अधिक जानकारी here पाया जा सकता है।

ParameterExpression dictExpr = Expression.Parameter(typeof(Dictionary<string, int>)); 
ParameterExpression keyExpr = Expression.Parameter(typeof(string)); 
ParameterExpression valueExpr = Expression.Parameter(typeof(int)); 

// Simple and direct. Should normally be enough 
// PropertyInfo indexer = dictExpr.Type.GetProperty("Item"); 

// Alternative, note that we could even look for the type of parameters, if there are indexer overloads. 
PropertyInfo indexer = (from p in dictExpr.Type.GetDefaultMembers().OfType<PropertyInfo>() 
         // This check is probably useless. You can't overload on return value in C#. 
         where p.PropertyType == typeof(int) 
         let q = p.GetIndexParameters() 
         // Here we can search for the exact overload. Length is the number of "parameters" of the indexer, and then we can check for their type. 
         where q.Length == 1 && q[0].ParameterType == typeof(string) 
         select p).Single(); 

IndexExpression indexExpr = Expression.Property(dictExpr, indexer, keyExpr); 

BinaryExpression assign = Expression.Assign(indexExpr, valueExpr); 

var lambdaSetter = Expression.Lambda<Action<Dictionary<string, int>, string, int>>(assign, dictExpr, keyExpr, valueExpr); 
var lambdaGetter = Expression.Lambda<Func<Dictionary<string, int>, string, int>>(indexExpr, dictExpr, keyExpr); 
var setter = lambdaSetter.Compile(); 
var getter = lambdaGetter.Compile(); 

var dict = new Dictionary<string, int>(); 
setter(dict, "MyKey", 2); 
var value = getter(dict, "MyKey"); 

इंडेक्सर IndexExpression अनुक्रमित संपत्ति के मूल्य सीधे शामिल से पढ़ने के लिए:

+0

* "आम तौर पर" *, जब न? आप इस पर भरोसेमंद कैसे हो सकते हैं? –

+4

इसे इंडेक्सर पर 'इंडेक्सरनाम' विशेषता का उपयोग करके बदला जा सकता है। आप उस श्रेणी पर प्रतिबिंबित कर सकते हैं जिसमें इंडेक्सर है और 'डिफॉल्टमेम्बर' विशेषता को पुनर्प्राप्त करने के लिए सूचकांक संपत्ति का नाम विश्वसनीय रूप से प्राप्त करने के लिए। अधिक जानकारी के लिए [यहां] देखें (http://social.msdn.microsoft.com/Forums/en-US/vstscode/thread/60de101a-278d-4674-bc1a-0a04210d566c)। –

+0

बहुत बहुत धन्यवाद। यह वास्तव में काम करता है - अभिव्यक्ति। प्रॉपर्टी (पैरामीटर, "आइटम", अभिव्यक्ति। कॉन्स्टेंट (...)) – Ondra

12

मैं कैसे एक इंडेक्सर का उपयोग करने पर एक पूर्ण उदाहरण पोस्ट करेंगे। इसे लिखने के लिए हमें Expression.Assign का उपयोग करना होगा। बाकी सब कुछ काफी वेनिला Expression है। डैनियल द्वारा लिखे गए इंडेक्सर को आम तौर पर "आइटम" कहा जाता है। नोट Expression.Property एक अधिभार कि सीधे इंडेक्सर (ताकि "Item") के नाम पर स्वीकार करता है, लेकिन मैं इसे स्वयं को खोजने के लिए चुना है (इसलिए यह पुन: उपयोग किया जा सकता है)। मैंने आपके द्वारा इच्छित इंडेक्सर के सटीक अधिभार को खोजने के लिए LINQ का उपयोग करने के तरीके पर भी एक उदाहरण दिया है।

बस एक जिज्ञासा के रूप में

, यदि आप Dictionary के लिए उदाहरण के लिए MSDN पर देखो, Properties के तहत आप मिल जाएगा Item

संबंधित मुद्दे