2013-02-11 2 views
7

Я работаю с объектом expando, и я пытаюсь определить вычисленное свойство.Определить вычисленное свойство объекта expando

Я знаю, что я могу определить простое свойство делать что-то вроде следующего:

dynamic myExpando = new ExpandoObject(); 
myExpando.TheAnswerToLifeTheUniverseAndEverything= 42; 

Аналогично, можно также определить метод:

myExpando.GetTheQuestion = ((Func<string>)(() => 
     { 
      return "How many road must a man walk down before we can call him a man?"; 
     })); 

При работе со стандартным объектом мы может определить вычисленное свойство, то есть определить свойство, которое вернет результаты пользовательского метода/calc. Нет необходимости в примере.

Мне нужно сделать что-то подобное на моем expando - имея свойство, которое на самом деле вызывает «Func» (или какую-то другую форму делегата, все идет, как только я могу вызвать пользовательский метод и иметь пользовательский тип возврата) , Поэтому в основном мне нужно вызвать метод, как во втором примере, но работать он как свойство.

В принципе мне нужно быть в состоянии назвать его myExpando.GetTheQuestion вместо myExpando.GetTheQuestion(), сохраняя при этом возможность определения пользовательского делегата в качестве органа собственности.

Есть ли способ сделать это? Я верю, что я мог бы сделать это с помощью деревьев выражений, но я признаю, что я немного потерялся там. Может ли кто-нибудь дать некоторые рекомендации о том, как достичь этого?


EDIT

Совершено некоторые дополнительные исследования .. Если нет какого-то очень специфический класс/интерфейс/синтаксисом, что я не знаю, я начинаю думать, что выше, невозможно. Из того, что я получаю, класс ExpandoObject работает, определяя некоторые методы, которые делают фоновое водоснабжение - TryGetMember, TrySetMember и т. Д. Теперь, когда «доступ к свойству» в динамическом объекте, TryGetMember - это memeber, который вызывается. Этот член возвращает значение из своего рода внутреннего словаря (да, я знаю ... это немного упрощено, но должно дать идею) ... нет теста на тип возвращаемого значения. Это означает, что в моем примере myExpando.GetTheQuestion вернет оригинальный Func.

Казалось бы, поскольку TryGetMember просто возвращает значение, нет способа заставить его «выполнить» код свойства. Для этого вам понадобится какой-то суррогат expression/lambda/func/action, значение которого фактически является РЕЗУЛЬТАТОМ метода. Что кажется невозможным (и не будет иметь большого смысла, если я не пропущу что-то - в основном у вас будет значение, которое задано как «делегат», а затем получается как возвращаемое значение делегата ???). Правильно ли это, или я чего-то не хватает?

ответ

2

Вы должны сделать свой собственный ExpandoObject, наследуя DynamicObject и первостепенную

public override bool TryGetMember(GetMemberBinder binder, out object result) и public override bool TrySetMember(SetMemberBinder binder, object value)

Implement TrySetMember для хранения значения в частном Dictionary<string,object> под binder.Name и использовать TryGetMember, чтобы извлечь его из этого словаря, что даст вам базовый объект ExpandoObject.Затем, чтобы дать ему необходимую функцию, добавьте чек в TryGetMember, после того, как вы потянете объект, чтобы увидеть, , а затем используйте отражение, чтобы увидеть, не принимает ли он никаких аргументов. Если оба значения true, то просто добавьте dynamic и не добавьте круглую скобку аргумента arg и назначьте ее result.

public override bool TryGetMember(GetMemberBinder binder, out object result) 
{ 
     if (_dictionary.TryGetValue(binder.Name, out result)){ 
      if(result is Delegate && /* some reflection check on args*/){ 
       result = ((dynamic)result)(); 
      } 
     } 
} 

У меня есть с открытым исходным кодом рамки ImpromptuInterface (в NuGet), который имеет негерметичнойImpromptuDictionary, которые вы могли бы начать с как вашим ExpandoObject вместо этого, особенно если вам нужно какое-либо из более детальных особенностей ExpandoObject таких как поддержка привязки gui. У него также есть больше dlr plumbing features, которые могут вам пригодиться.

+0

Да, на самом деле я, хотя и о подобном решении, - но мне было интересно, возможно ли это, если бы не пользовательский код (не то, что я не мог его добавить), ведь мой объект expando уже является обычным унаследованным классом), используя выражение деревья и т. д. Во всяком случае, если никакой другой способ не будет опубликован, я соглашусь на это как на лучшее.^_^ – SPArchaeologist

+0

Хорошо, теперь я приму это. Это обходной путь, но я полагаю, что это также единственный способ вести «рассчитанное свойство», как нормальное свойство. Поскольку я уже расширил базу expando для поддержки других действий (я использую безопасный expando, который возвращает null для неопределенных свойств), я думаю, что я мог бы пойти с этим (на самом деле это была моя первая идея, но я все равно разместил вопрос если я чего-то не хватает). Поблагодарите jbtule, я также посмотрю на ваш lib - всегда есть чему поучиться. – SPArchaeologist