2012-01-18 10 views
6

Nie jestem pewien, czy powinienem zapytać o to tutaj, ale tutaj idziemy, podczas gdy jednostka testuje prywatną statyczną metodę, która ma jako parametr krótki, otrzymuję MissingMethodException tylko wtedy, gdy parametr wynosi 0.Czy to błąd? MissingMethodException uzyskujący dostęp do prywatnej statycznej metody z 0 jako parametrem

używam VS 2010 SP1 kierowania Framework 4 (pełna), tutaj jest minimum kod odtworzyć ten błąd (podnosimy kod VB6 więc nie bądź niegrzeczny):

[DataContract] 
    public enum NotificationResult 
    { 
    [EnumMember] 
    Success, 
    [EnumMember] 
    StoredError, 
    [EnumMember] 
    InvalidId, 
    [EnumMember] 
    OperationError, 
    } 

    public sealed class NotificationContext 
    { 
    private static NotificationResult GetExecuteResult(short result) 
    { 
     NotificationResult executeResult; 
     switch (result) 
     { 
     case 0: 
      executeResult = NotificationResult.Success; 
      break; 
     case 1: 
      executeResult = NotificationResult.StoredError; 
      break; 
     case 2: 
      executeResult = NotificationResult.InvalidId; 
      break; 
     default: 
      executeResult = NotificationResult.OperationError; 
      break; 
     } 

     return executeResult; 
    } 
    } 

Oto jak ja testowania kodu:

PrivateType privateHelperType = new PrivateType(typeof(NotificationContext)); 
     var actual = (NotificationResult)privateHelperType.InvokeStatic(
     "GetExecuteResult", (short)1); 
     var actual2 = (NotificationResult)privateHelperType.InvokeStatic(
     "GetExecuteResult", (short)0); //here is where i get the exception 

W pierwszym wywołaniu otrzymuję oczekiwany wynik, w drugim wywołaniu otrzymuję wyjątek (dodałem rzut do krótkiego myślenia, że ​​być może wyjątek był, ponieważ nie znaleziono metody z int jako parametrem).

Czy ktoś jest w stanie odtworzyć zachowanie ?, czy robię coś nie tak?

Dzięki za pomoc.

+0

Nie testuj metod prywatnych. – jason

+1

@Jason Wiem, ale tak jak powiedziałem, aktualizujemy aplikację VB6 i ta metoda nie uzyskała 100% pokrycia i musimy zweryfikować, że działała tak, jak określono. –

+0

Nie potrzebujesz 100% pokrycia prywatnych metod; tylko twoje nieprywatne metody. – jason

Odpowiedz

8

Problemem jest to, że istnieją dwa przeciążenia tej metody (istnieją inne, ale one nie mają znaczenia tutaj):

Różnica polega na tym, że drugie przeciążenie ma parametr typu BindingFlags, który jest enum. A gdy jako drugi parametr zostanie podany literalny 0, to przeciążenie jest wybierane, ponieważ literalne 0 jest domyślnie wymienialne na dowolne enum i nie używając params jest uważane za lepsze niż użycie go w rozdzielczości przeciążania. Tak więc, w zasadzie

  • privateType.InvokeStatic("GetExecuteResult", 1) jest kompilowany do privateType.InvokeStatic("GetExecuteResult", new object[] { 1 })
  • privateType.InvokeStatic("GetExecuteResult", 0) jest kompilowany do privateType.InvokeStatic("GetExecuteResult", 0, new object[] { })

to jest przyczyną problemu. Myślę najczystszym sposobem na uniknięcie byłoby stworzyć tablicę wyraźnie:

privateType.InvokeStatic("GetExecuteResult", new object[] { 0 }) 

wyjątkiem kodu nie zdać dosłowne 0 metody, oddasz go w pierwszej kolejności. Zgodnie ze specyfikacją przeciążenie BindingFlags nie powinno być wybierane w tym przypadku.Ale errors like this are a known bug, które nie zostaną naprawione, ponieważ może przerwać działanie niektórych programów.

+0

Uważam, że błąd, którego szukasz, polega na tym, że stała 0 (nawet z rzutem), jak pierwotnie wyrażono w pytaniu, przechodzi do przeciążenia enum. Zobacz [this] (http://stackoverflow.com/questions/2043554/method-overload-resolution-uenexpected-behavior), które wskazuje na [to] (http://blogs.msdn.com/ericlippert/archive/2006 /03/29/the-root-of-all-evil-part-two.aspx). –

+0

@AnthonyPegram, ten artykuł z Erica Lipperta jest tym, o którym myślałem. Dodałem do niej link do odpowiedzi. – svick

+0

masz rację, oznaczoną jako odpowiedź, ponieważ jest bardziej kompletna –

-3

Chciałbym spróbować uczynić twoją klasę niezapieczoną. To jest czysto domysły, ale może to podklasy twój NotificationContext jako część PrivateType.

Moja druga rekomendacja to pobranie czegoś podobnego do dotpeek: http://blogs.jetbrains.com/dotnet/2011/05/free-net-decompiler-is-available-for-early-access/, aby zobaczyć, jak wygląda PrivateType. Zrozumienie, jak to działa, pomoże nam zrozumieć, co się właściwie dzieje.

+1

Dlaczego "zapieczętowane" ma znaczenie przy powoływaniu się na metodę staiczną? – svick

+0

Taaaaaaaaaaaaaa, że ​​mózg tam zniknie ... Wciąż sprawdzanie źródła jest dobrym początkiem. – Dessus

3

Interesujące ... Udało mi się to odtworzyć i znalazłem sposób, aby to naprawić.

short s = 0; 
var actual2 = (NotificationResult)privateHelperType.InvokeStatic(
     "GetExecuteResult", s); 
+0

Zabawne, nigdy tego nie próbowałem, ponieważ używałem wewnętrznej klasy statycznej z wszystkimi moimi stałymi, w mojej klasie miałem tę "wewnętrzną const short Success = 0;" i nadal otrzymuję błąd. –

+0

Myślę, że to dlatego, że typem parametru jest obiekt. Podczas rzucania nie zmienia ona typu instancji obiektu. Po prostu pozwala na odwołanie się do instancji obiektu przez zmienną tego typu. Po przejściu obiektu przekazujesz odwołanie do wartości w pamięci typu Int16. –

Powiązane problemy