2011-11-16 2 views
6

Rozważmy następujący:Dlaczego każde oddzielne wywołanie dynamiczne powoduje dwa wyjątki i czy można je zignorować?

using System; 
using System.Dynamic; 
using System.Linq; 

namespace DynamicObjectTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      dynamic dyn = new TestDynamic(); 
      Console.ReadKey(); 

      foreach (var i in Enumerable.Range(0, 100)) 
      { 
       Console.WriteLine(dyn.Foo()); 
       Console.WriteLine(dyn.Bar()); 
      } 

      Console.ReadKey(); 
     } 
    } 

    class TestDynamic : DynamicObject 
    { 
     public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
     { 
      if (binder.Name == "Foo") 
      { 
       result = "Bar"; 
       return true; 
      } 
      else if (binder.Name == "Bar") 
      { 
       result = "Foo"; 
       return true; 
      } 

      return base.TryInvokeMember(binder, args, out result); 
     } 
    } 
} 

Po uruchomieniu tego programu, cztery wyjątki typu RuntimeBinderException są wyrzucane. Można zaobserwować to zarówno poprzez złamanie wszystkich wyrzuconych wyjątkami (Debug/wyjątki .../sprawdzić wyjątków Common Language Runtime Rzut wyboru) lub przy użyciu perfmon:

enter image description here

Teraz te są oczywiście wyjątki złowione i poddane obróbce wewnętrznie, ponieważ metoda TryInvokeMember jest wywoływana później. Wydaje się jednak, że jest to bardzo uciążliwe i niewłaściwe korzystanie z wyjątków, jeśli subskrybujesz mantrę "używaj wyjątków tylko w wyjątkowych okolicznościach". Dla mojego konkretnego przykładu to naprawdę nie problem, ponieważ ci sami członkowie - Foo i Bar - są wielokrotnie wywoływani. Mam jednak na myśli inne scenariusze, w których członkowie są znacznie mniej statyczni.

Czy jest coś, co można zrobić, aby środowisko wykonawcze wywołało TryInvokeMember, nie rzucając żadnych wyjątków?

+1

Istnieje pewna wewnętrzna wyjątkowa sprawa, że ​​połykają. Możesz zdekodować kod 'TryInvokeMember', aby zobaczyć, co się dzieje. – Polynomial

+0

Jeśli użyję checkboxa/rzuconego podejścia, to tak naprawdę nie będzie dla mnie łamać. –

+1

@ Polinomial: Zwróciłem uwagę, że to jest wewnętrzne w moim pytaniu, ale to nie jest moje pytanie. –

Odpowiedz

2

System czasami wyrzuca i przechwytuje wyjątki wewnętrznie. Nie możesz nic zrobić (z wyjątkiem przesyłania opinii do http://connect.microsoft.com/VisualStudio, ale nie ma podstaw, ponieważ jest to mało prawdopodobne, aby wpłynąć na wydajność - inne koszty związane z DynamicObject znacznie przekraczają tę wartość).

(Gdybym musiał zgadnąć, wewnętrznie może to wyglądać jak wyjątek sprzętowy "błąd strony" pamięci: system dopuszcza wyjątek, a następnie go łapie i łączy, aby przyszłe wykonanie się powiodło. być wyjątkowo wydajnym, ponieważ wykorzystuje on wyjątkowe funkcje procesora, dzięki czemu w kodzie nie jest wymagane rozgałęzienie warunkowe).

UWAGA: Aby wypróbować kod w oryginalnym poście, należy wyłączyć opcję "Just My Code" "opcja, jak również konfiguracja, aby złamać wszystkie zgłaszane wyjątki.

+0

Czy możesz podać odniesienia do dalszej lektury na temat twojej odpowiedzi? W szczególności chciałbym przeczytać o innych obciążeniach związanych z DynamicObject, a także o tym, jak są wykonywane funkcje wyjątku CPU. Dzięki! – defines