2011-07-20 12 views
10

私はフィルタリング機能に取り組んでいます。フィルタは、ユーザーが作成した式ツリーになります。ユーザーがフィルタリングに使用できる約30のフィールドがあります。最良の方法は、インデクサーでオブジェクトモデルを作成し、enum型のインデックスで必要な値にアクセスすることです。式ツリーからインデクサーにアクセスする

は、この例を参照してください:

enum Field 
{ 
    Name, 
    Date, 
} 

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

私は式ツリーからインデクサにアクセスする方法をお願いしたいと思います。

答えて

15

インデクサーは、通常Itemと呼ばれる単純なプロパティです。つまり、その名前を使用して他のプロパティと同様にインデクサにアクセスできます。

indexerプロパティの名前は、IndexerName attributeを使用してクラスの実装者によって変更できます。

インデクサープロパティの実際の名前を確実に取得するには、クラスを反映してDefaultMember attributeを取得する必要があります。
詳細情報はhereです。

+0

*「通常」*、それがないときに見つけることができますか?どうやってそれを確実に得ることができますか? –

+4

インデクサーの 'IndexerName'属性を使って変更できます。インデクサを含むクラスを反映させ、 'DefaultMember'属性を取得してインデクサプロパティの名前を確実に取得することができます。詳細については、[ここ](http://social.msdn.microsoft.com/Forums/en-US/vstscode/thread/60de101a-278d-4674-bc1a-0a04210d566c)を参照してください。 –

+0

ありがとうございました。それは実際に動作します - Expression.Property(パラメータ、 "Item"、Expression.Constant(...)) – Ondra

12

私は、インデクサーを使用する方法についての完全な例を投稿します:

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が直接インデックス付きプロパティの値が含まれているインデクサから読み込むには。それに書き込むにはExpression.Assignを使用する必要があります。他のすべてはかなりバニラExpressionです。 Danielによって書かれているように、Indexerは通常 "Item"と呼ばれています。 Expression.Propertyにはインデクサーの名前を直接受け入れる過負荷があるので("Item")、手動で検索することにしました(再利用できるようにしました)。私はあなたが望むインデクサの正確なオーバーロードを見つけるためにLINQの使い方の例を書いています。

あなたがProperties下、Dictionaryのために例えばMSDNに見ればただの好奇心として、あなたはItem

関連する問題