Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a bug? MissingMethodException accessing a private static method with 0 as parameter

I'm not sure if I should ask this here but here we go, while unit testing a private static method that has as parameter a short I'm getting a MissingMethodException only when this parameter is 0.

I'm using VS 2010 SP1 targeting the Framework 4 (full), here is the bare minimum code to reproduce this error (we are upgrading a VB6 code so don't be rude):

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

Here is how I'm testing the code:

 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

In the first invocation i get the expected result, in the second invocation I get the exception (I added the cast to short thinking that maybe the exception was because it was not finding a method with an int as a parameter).

Is anybody able to reproduce the behavior?, am I doing something wrong?

Thanks for your help.

like image 798
Juan Zamudio Avatar asked Jan 18 '12 03:01

Juan Zamudio


2 Answers

The problem is that there are two overloads of this method (there are others, but they don't matter here):

  • public Object InvokeStatic(string name, params Object[] args)
  • public Object InvokeStatic(string name, BindingFlags invokeAttr, params Object[] args)

The difference is that the second overload has a parameter of type BindingFlags, which is an enum. And when you pass literal 0 as the second parameter, this overload is chosen, because the literal 0 is implicitly convertible to any enum and not using params is deemed better than using it in overload resolution. So, basically

  • privateType.InvokeStatic("GetExecuteResult", 1) is compiled into privateType.InvokeStatic("GetExecuteResult", new object[] { 1 })
  • privateType.InvokeStatic("GetExecuteResult", 0) is compiled into privateType.InvokeStatic("GetExecuteResult", 0, new object[] { })

This is the cause of your problem. I think the cleanest way to avoid it would be to create the array explicitly:

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

Except in your code you don't pass the literal 0 to the method, you cast it first. According to the specification, the BindingFlags overload should not be chosen in this case. But errors like this are a known bug, that won't be fixed, because it would break some working programs.

like image 97
svick Avatar answered Sep 18 '22 22:09

svick


Interesting... I was able to reproduce it, and I found a way to fix it.

short s = 0;
var actual2 = (NotificationResult)privateHelperType.InvokeStatic(
        "GetExecuteResult", s);
like image 36
Nick Bray Avatar answered Sep 19 '22 22:09

Nick Bray