2013-02-11 10 views
7

Pracuję z obiektem expando i próbuję zdefiniować obliczoną właściwość.Definiowanie obliczonej właściwości w obiekcie expando

wiem, że mogę zdefiniować prostą właściwość wykonując coś jak następuje:

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

Podobnie, można również zdefiniować metodę:

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

podczas pracy ze standardowym obiektu my może zdefiniować właściwość obliczoną, tj. zdefiniować właściwość, która zwróci wyniki niestandardowej metody/obliczenia. Nie ma potrzeby na przykład.

Potrzebuję zrobić coś podobnego na moim expando - mając właściwość, która faktycznie nazywa "Func" (lub jakąś inną formę delegata, wszystko idzie tak szybko, jak mogę wywołać niestandardową metodę i mieć niestandardowy typ zwrotu) . Więc w zasadzie muszę wywołać metodę, jak w drugim przykładzie, ale czy działa jak własność.

Zasadniczo muszę być w stanie wywołać go z myExpando.GetTheQuestion zamiast myExpando.GetTheQuestion(), zachowując zdolność definiowania niestandardowych delegata jako ciało materialne.

Czy istnieje sposób, aby to zrobić? Wierzę, że mogę może zrobić to za pomocą drzew wyrażeń, ale przyznaję, że jestem trochę zagubiony. Czy ktoś może udzielić wskazówek, jak to osiągnąć?


EDIT

Sporządzono trochę więcej badań .. O ile nie jest jakaś bardzo specyficzna klasa/interfejs/sintax że nie wiem, ja zaczynam myśleć, że powyższe jest niemożliwe. Z tego, co otrzymuję, klasa ExpandoObject działa, definiując niektóre metody, które działają w tle - TryGetMember, TrySetMember i inne. Teraz, gdy "uzyskując dostęp do właściwości" na dynamicznym objetc, TryGetMember jest elementem, który zostanie wywołany. Ten element zwraca wartość z pewnego rodzaju wewnętrznego słownika (tak, wiem ... to jest trochę uproszczone, ale powinien dać pomysł) ... brak testu na typ zwróconej wartości. Oznacza to, że w moim przykładzie myExpando.GetTheQuestion zwróci oryginalny Func.

Wygląda na to, że ponieważ TryGetMember właśnie zwraca wartość, nie ma sposobu, aby uczynić ją "wykonaniem" kodu właściwości. Aby to osiągnąć, potrzebujesz jakiegoś surogatu expression/lambda/func/action, którego wartość jest faktycznie WYNIKIEM metody. Co wydaje się niemożliwe (ani nie miałoby większego sensu, chyba że coś mi umknęło - po prostu miałbyś wartość, która jest ustawiona na "delegata", a następnie dostajesz jako wartość zwracaną przez delegata ???). Czy mam rację, czy to albo coś mi brakuje?

Odpowiedz

2

Musisz zrobić własną ExpandoObject, przez dziedziczenie DynamicObject i przesłanianie

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

wdrożyć TrySetMember do przechowywania wartości w prywatnym Dictionary<string,object> pod binder.Name i używać TryGetMember aby pobrać ją z tego słownika, to da ci podstawowy ExpandoObject.Następnie, aby nadać mu potrzebną funkcję, dodaj element sprawdzający TryGetMember, po pociągnięciu obiektu, aby sprawdzić, czy to jest , a następnie użyj odbicia, aby sprawdzić, czy nie przyjmuje żadnych argumentów. Jeśli oba są prawdziwe, po prostu odrzuć je do dynamic i nie dodawaj nawiasów wywołujących arg i przypisz je do 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)(); 
      } 
     } 
} 

Mam ramową ImpromptuInterface open source (w Nuget), który ma niezgrzewaneImpromptuDictionary który mógłby zacząć jako ExpandoObject zamiast, zwłaszcza jeśli potrzebujesz któregokolwiek z bardziej zróżnicowany cech ExpandoObject takie jako wsparcie wiązania GUI. Ma również więcej dlr plumbing features, które mogą ci się przydać.

+0

Tak, tak naprawdę chodzi mi o podobne rozwiązanie - ale zastanawiałem się, czy powinno to być możliwe bez niestandardowego kodu (nie, że nie mogłem go dodać - po tym jak cały mój obiekt expando jest już niestandardową odziedziczoną klasą) za pomocą wyrażenia drzewa i takie. W każdym razie, jeśli nie zostanie opublikowany inny sposób, zaakceptuję to jako najlepsze dopasowanie^_^ – SPArchaeologist

+0

Ok, na razie to zaakceptuję. Jest to obejście, ale przypuszczam, że jest to również jedyny sposób, aby "obliczona właściwość" zachowywała się jak normalna właściwość. Ponieważ już rozszerzyłem bazę expando, aby obsługiwać inne zachowania (używam bezpiecznego expando, które zwraca null dla niezdefiniowanych właściwości), myślę, że mogłem z tym pójść (w rzeczywistości to był mój pierwszy pomysł, ale mimo to opublikowałem pytanie, aby zobaczyć jeśli czegoś mi brakowało). Dziękuję jbtule, popatrzę też na twoją bibliotekę - zawsze jest coś do nauczenia się. – SPArchaeologist

Powiązane problemy