2009-06-07 19 views
6

Czy ktoś wie o sposobie przechwycenia dynamic wywołań metod (szczególnie tych, które będą podnosić RuntimeBinderException s) z RealProxy? Miałem nadzieję uchwycić wyjątek i wprowadzić "brakującą metodę", ale wydaje się, że został rzucony, zanim przechwytujący dostanie zgłoszenie.Brakujące metody w C# 4.0: dynamiczne kontra RealProxy

Moja próba właśnie wygląda:

dynamic hello = MethodMissingInterceptor<DynamicObject>.Create(); 
Assert.AreEqual("World", hello.World()); 

Gdzie World nie jest w rzeczywistości realizowana na DynamicObject. Interceptor jest dość prosta - Miałem nadzieję, by sprawdzić IMethodReturnMessage.Exception dla RuntimeBinderException i przekazania do czegoś podobnego:

public IMessage MethodMissing(IMethodCallMessage call) 
{ 
    return new ReturnMessage(call.MethodBase.Name, new object[0], 0, call.LogicalCallContext, call); 
} 

Niestety, wszystko co widzę w moim kolektora kilka połączeń do GetType, a nie nieistniejąca World metoda .

W przypadku awarii - czy ktoś wie, czy istnieje wersja DynamicProxy działająca szczęśliwie na platformie .NET 4.0, która mogła rozwiązać ten problem?

Odpowiedz

17

Zacznę od długiej odpowiedzi. Każdy wiążą dynamicznego działania w C# robi około te trzy rzeczy w tej kolejności:

  1. Zadaj obiektu wiązać się jeżeli realizuje IDynamicMetaObjectProvider lub jest obiektem COM, a jeśli to się nie powiedzie, to ...
  2. Powiąż operację z operacją na zwykłym, starym obiekcie clr za pomocą odbicia, a jeśli to się nie powiedzie, to ...
  3. Powoduje zwrócenie obiektu DynamicMetaObject, który reprezentuje całkowity brak powiązania.

Wyświetlane są wywołania GetType, ponieważ w kroku 2 moduł wykonawczy kodu wykonawczego C# zastanawia się nad użytkownikiem, aby dowiedzieć się, czy istnieje metoda "Światowa" odpowiednia do wywoływania, a dzieje się tak, ponieważ implementacja cześć IDynamicMetaObjectProvider, jeśli istnieje, nie może wymyślić coś specjalnego do zrobienia.

Niestety dla ciebie, do czasu wyrzucenia wyjątku RuntimeBinderException, nie jesteśmy już wiążące. Wyjątek pochodzi z fazy wykonawczej operacji dynamicznej, w odpowiedzi na zwrócony obiekt meta z kroku 3. Jedyną możliwością złapania go jest faktyczna strona wywołania.

Taka strategia nie zadziała, jeśli chcesz zastosować metodę method_missing w języku C#. Masz jednak kilka opcji.

Jedną z łatwych opcji jest zaimplementowanie IDynamicMetaObjectProvider w metodzie MethodMissingInterceptor i opóźnienie implementacji owiniętego obiektu przez IDMOP. W przypadku niepowodzenia ze strony wewnętrznej IDMOP, możesz powiązać to, co chcesz (być może wywołanie delegata method_missing zapisanego w przechwytywaczu). Wadą tego jest to, że działa to tylko dla obiektów, które są znane jako obiekty dynamiczne, np. te, które na początku wdrażają IDMOP. Dzieje się tak dlatego, że zasadniczo wstawiasz siebie pomiędzy krokami 1 i 2.

Inną alternatywą, o której mogę pomyśleć, to zaimplementowanie IDynamicMetaObjectProvider, a w niej pozytywnie reaguję na każde wiązanie, zwracając wywołanie metody, która (a) produkuje ten sam kod, który kompilator C# wygenerowałby, by wiązał się w pierwszej kolejności, oraz (b) przechwytuje RuntimeBinderException, aby wywołać metodę method_missing.Minusem jest to, że byłoby to dość skomplikowane - trzeba wygenerować dowolne typy delegatów i IL, która ich używa, w stosunku do typów publicznych w zespole wrzutnika wykonawczego C#, które, szczerze mówiąc, nie są przeznaczone do publicznej konsumpcji. Ale przynajmniej otrzymasz brakującą metodę przeciwko wszystkim operacjom.

Jestem pewien, że istnieją inne strategie, o których nie myślałem, takie jak na przykład sugestie dotyczące używania serwerów proxy. Nie mogę sobie wyobrazić, jak wyglądają i nie mogę powiedzieć, czy odniosą sukces.

Sedno problemu polega na tym, że C# 4.0 nie ma projektu, który przewiduje twoje pragnienie, aby to zrobić. W szczególności nie można łatwo wstawić się między krokami 2 i 3. To prowadzi mnie do krótkiej odpowiedzi, która jest przykro, C# 4.0 nie ma method_missing.

+0

Dzięki za doskonałe wyjaśnienie, Chris - Właśnie zacząłem przeglądać wasze serie dynamicznych wpisów w blogu C#. :) Dla moich celów, twoje pierwsze rozwiązanie brzmi jak powinno działać. Naprawdę chcę tylko wykonywać te wezwania do obiektów w stylu budowniczym i dla pewnej dodatkowej płynności w testowaniu interfejsów API, nie muszę łapać ich na arbitralnych obiektach. – Thom

+0

@ Chris - zwróć uwagę także na pytanie "na wszelki wypadek" powyżej; właściwie, chciałbym to wiedzieć ;-p –

+0

Czy istnieje sposób na zapytanie obiektu dynamicznego o obecność elementu bez wywoływania go? –