wyślę kompletny przykład jak używać podziałowe:
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");
odczytu z indekser IndexExpression
zawiera bezpośrednio na wartość nieruchomości indeksowanej. Aby do niego pisać, musimy użyć Expression.Assign
. Wszystko inne jest całkiem waniliowe Expression
. Jak napisano przez Daniela, Indexer jest zwykle nazywany "Przedmiotem". Zauważ, że Expression.Property
ma przeciążenie, które akceptuje bezpośrednio nazwę indeksera (czyli "Item"
), ale wybrałem to ręcznie (aby mogło być ponownie użyte). Przedstawiłem nawet przykład użycia LINQ do znalezienia dokładnego przeciążenia indeksu, który chcesz.
tylko jako ciekawostkę, jeśli spojrzeć na MSDN na przykład dla Dictionary pod Properties znajdziesz Item
* „Normalnie” *, gdy nie jest ona? Jak mogłeś niezawodnie się z tym pogodzić? –
Można go zmienić za pomocą atrybutu 'IndexerName' na indeksatorze. Możesz zastanowić się nad klasą zawierającą indeksator i pobrać atrybut 'DefaultMember', aby niezawodnie uzyskać nazwę właściwości indeksu. Aby uzyskać więcej informacji, zobacz [tutaj] (http://social.msdn.microsoft.com/Forums/en-US/vstscode/thread/60de101a-278d-4674-bc1a-0a04210d566c). –
Wielkie dzięki. To naprawdę działa - Expression.Property (parametr, "Pozycja", Expression.Constant (...)) – Ondra