Это ошибка? MissingMethodException обращается к частному статическому методу с 0 в качестве параметра - PullRequest
6 голосов
/ 18 января 2012

Я не уверен, стоит ли мне задавать этот вопрос здесь, но здесь мы идем, пока при модульном тестировании частного статического метода, в качестве параметра которого используется short, я получаю исключение MissingMethodException, только когда этот параметр равен 0.

Я использую VS 2010 с пакетом обновления 1 (SP1) для платформы Framework 4 (полная версия), здесь приведен минимальный код для воспроизведения этой ошибки (мы обновляем код VB6, поэтому не грубите):

    [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;
    }
  }

Вот как я тестирую код:

 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

В первом вызове я получаю ожидаемый результат, во втором вызове я получаю исключение (я добавил приведение к краткому размышлению, что, возможно, исключение было из-за того, что он не находил метод с int в качестве параметра).

Кто-нибудь может воспроизвести поведение? Я что-то не так делаю?

Спасибо за вашу помощь.

Ответы [ 3 ]

8 голосов
/ 18 января 2012

Проблема в том, что у этого метода есть две перегрузки (есть и другие, но они здесь не имеют значения):

Разница в том, что вторая перегрузка имеет параметр типа BindingFlags, который является enum. И когда вы передаете литерал 0 в качестве второго параметра, эта перегрузка выбирается, потому что литерал 0 неявно конвертируется в любой enum, и использование params считается лучше, чем использование его в разрешении перегрузки. Итак, в основном

  • privateType.InvokeStatic("GetExecuteResult", 1) компилируется в privateType.InvokeStatic("GetExecuteResult", new object[] { 1 })
  • privateType.InvokeStatic("GetExecuteResult", 0) компилируется в privateType.InvokeStatic("GetExecuteResult", 0, new object[] { })

Это причина вашей проблемы. Я думаю, что самым чистым способом избежать этого было бы явное создание массива:

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

За исключением того, что в вашем коде вы не передаете литералу 0 методу, вы сначала его разыгрываете. Согласно спецификации, в этом случае не следует выбирать перегрузку BindingFlags. Но ошибки, подобные этой, являются известной ошибкой , которая не будет исправлена, потому что она может сломать некоторые работающие программы.

3 голосов
/ 18 января 2012

Интересно ... Мне удалось воспроизвести это, и я нашел способ исправить это.

short s = 0;
var actual2 = (NotificationResult)privateHelperType.InvokeStatic(
        "GetExecuteResult", s);
0 голосов
/ 18 января 2012

Я бы попробовал сделать твой класс не запечатанным.Это чисто предположение, но, возможно, это подкласс вашего NotificationContext как части PrivateType.

Моя вторая рекомендация - скачать что-то вроде dotpeek: http://blogs.jetbrains.com/dotnet/2011/05/free-net-decompiler-is-available-for-early-access/, чтобы взглянуть на то, как выглядит PrivateType.Понимание того, как это работает, поможет понять, что на самом деле происходит.

...