2012-01-18 15 views
6

No estoy seguro de si debería preguntar esto aquí, pero aquí vamos, mientras que la unidad de evaluación de un método estático privada que tiene como parámetro un corto me estoy poniendo un MissingMethodException sólo cuando este parámetro es 0.¿Es esto un error? MissingMethodException acceder a un método estático privado con 0 como parámetro

estoy usando VS 2010 SP1 focalización del Marco 4 (completo), aquí está el código mínimo para reproducir este error (que actualiza un código de Visual Basic 6 por lo que no ser grosero):

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

Así es como estoy probando el código:

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 

En la primera invocación i obtener el resultado esperado, en la segunda invocación tengo la excepción (añadí el reparto a corto pensar que tal vez la excepción fue porque no era encontrar un método con un int como parámetro).

¿Hay alguien capaz de reproducir el comportamiento ?, estoy haciendo algo mal?

Gracias por su ayuda.

+0

No pruebe los métodos privados. – jason

+1

@Jason lo sé, pero como he dicho, estamos actualizando una aplicación VB6 y este método no estaba obteniendo el 100% de cobertura y necesitamos verificar que funcionó según lo especificado. –

+0

No necesita una cobertura del 100% en sus métodos privados; solo sus métodos no privados. – jason

Respuesta

8

El problema es que hay dos sobrecargas de este método (hay otros, pero ellos no importan aquí):

El La diferencia es que la segunda sobrecarga tiene un parámetro del tipo BindingFlags, que es un enum. Y cuando se pasa literal 0 como segundo parámetro, se elige esta sobrecarga, ya que el literal 0 es convertir implícitamente a cualquier enum y no usar params se considera mejor que usarlo en la resolución de sobrecarga. Así que, básicamente

  • privateType.InvokeStatic("GetExecuteResult", 1) se compila en privateType.InvokeStatic("GetExecuteResult", new object[] { 1 })
  • privateType.InvokeStatic("GetExecuteResult", 0) se compila en privateType.InvokeStatic("GetExecuteResult", 0, new object[] { })

Ésta es la causa de su problema. Creo que la forma más limpia para evitar que sería para crear la matriz de forma explícita:

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

Excepto en su código que no pasa el literal 0 al método, lo lanzas en primer lugar. De acuerdo con la especificación, la sobrecarga BindingFlags no debe elegirse en este caso.Pero errors like this are a known bug, eso no se solucionará, porque rompería algunos programas en funcionamiento.

+0

Creo que el error que está buscando es que la constante 0 (incluso con el molde) como se expresó originalmente en la pregunta va a la sobrecarga de la enumeración. Ver [this] (http://stackoverflow.com/questions/2043554/method-overload-resolution-unexpected-behavior), que apunta a [esto] (http://blogs.msdn.com/ericlippert/archive/2006 /03/29/the-root-of-all-evil-part-two.aspx). –

+0

@AnthonyPegram, ese artículo de Eric Lippert es en el que estaba pensando. He agregado un enlace a la respuesta. – svick

+0

tiene razón, marcado como respuesta porque es más completo –

-3

Me gustaría intentar que su clase no esté sellada. Esto es solo una suposición, pero quizás esté subclasificando su NotificationContext como parte de PrivateType.

Mi segunda recomendación es descargar algo así como dotPeek: http://blogs.jetbrains.com/dotnet/2011/05/free-net-decompiler-is-available-for-early-access/ a echar un vistazo a lo que PrivateType se parece. Comprender cómo funciona ayudará a resolver lo que realmente está sucediendo.

+1

¿Por qué 'sellado' importará al invocar un método estático? – svick

+0

Sí, buen punto, el cerebro se desvanece allí ... Todavía inspeccionar la fuente es un buen comienzo. – Dessus

3

Interesante ... yo era capaz de reproducirla, y he encontrado una manera de solucionarlo.

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

gracioso, nunca lo intenté porque estaba usando una clase estática interna con todas mis constantes, en mi clase tenía este "const int corto success = 0;" y aún obteniendo el error. –

+0

Creo que es porque el tipo del parámetro es el objeto. Cuando lo lanzas, no cambia el tipo de la instancia del objeto. Solo permite que la instancia del objeto sea referenciada por una variable de ese tipo. Cuando pasa el objeto pasa por referencia un valor en la memoria de tipo Int16. –

Cuestiones relacionadas