2012-05-10 18 views
7

Se ejecutó en un problema de tiempo de ejecución interesante después de algunas refactorizaciones y se ha incluido en la siguiente situación.Al pasar un parámetro dinámico lanza RuntimeBinderException al llamar al Método desde la interfaz heredada

Al pasar una propiedad de un objeto dinámico a un método en una interfaz que se ha heredado de una interfaz principal, el archivo de tiempo de ejecución no puede encontrar el método.

Aquí está una prueba para demostrar tanto fracaso y el éxito (al llamar directamente al método del tipo de interfaz padres)

using System.Dynamic; 
using Microsoft.CSharp.RuntimeBinder; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace Test.Utility 
{ 
    public interface IEcho 
    { 
     string EchoString(string input); 
    } 

    public interface IInheritEcho : IEcho 
    { } 

    public class EchoClass : IInheritEcho 
    { 
     public string EchoString(string input) 
     { 
      return input; 
     } 
    } 

    [TestClass] 
    public class RuntimeBinderTest 
    { 
     [TestMethod] 
     public void RuntimeBinder_should_work_when_dynamic_parameters_are_passed_to_method_from_inherited_interface() 
     { 
      //Arrange 
      dynamic dynObject = new ExpandoObject(); 
      dynObject.Foo = "Bar"; 
      IInheritEcho echomore = new EchoClass(); 

      string echo = null; 
      string exceptionMessage = null; 

      //Act 
      try 
      { 
       echo = echomore.EchoString(dynObject.Foo); 
      } 
      catch (RuntimeBinderException e) 
      { 
       exceptionMessage = e.Message; 
      } 

      //Assert 
      Assert.AreEqual(echo, dynObject.Foo, false, exceptionMessage); 
     } 

     [TestMethod] 
     public void RuntimeBinder_should_work_when_dynamic_parameters_are_passed_to_method_from_noninherited_interface() 
     { 
      //Arrange 
      dynamic dynObject = new ExpandoObject(); 
      dynObject.Foo = "Bar"; 
      IEcho echomore = new EchoClass(); 

      string echo = null; 
      string exceptionMessage = null; 

      //Act 
      try 
      { 
       echo = echomore.EchoString(dynObject.Foo); 
      } 
      catch (RuntimeBinderException e) 
      { 
       exceptionMessage = e.Message; 
      } 

      //Assert 
      Assert.AreEqual(echo, dynObject.Foo, false, exceptionMessage); 
     } 
    } 
} 

Prueba # 1 se produce un error: Assert.AreEqual falló. Esperado: < (nulo)>. Real:. 'Test.Utility.IInheritEcho' no contiene una definición para 'EchoString'

Prueba # 2 Sucede.

Mi pregunta es si mi suposición de que la primera prueba debe pasar es correcta o hay una razón fundamental en el marco que no lo es?

Sé que puedo solucionar el problema lanzando los parámetros cuando los transfiero o los asigno a variables antes de pasarlos. Tengo más curiosidad por el motivo por el que la interfaz heredada está causando la falla de RuntimeBinder. ..

+0

tienes toda la razón. (Aunque es de una versión anterior de C#: http://msdn.microsoft.com/en-us/library/aa664578%28VS.71%29.aspx) Debe haber una falla. ¿Qué sucede si utiliza una clase normal con una propiedad de cadena en lugar del objeto expando? ¿Encuentra el método en la interfaz heredada? (No tengo VS aquí para hacer la prueba yo mismo). Si fue con enlace estático (enlace de tiempo de compilación), entonces hay algo mal con el enlace dinámico (cuaderno de tiempo de ejecución). – JotaBe

+0

El uso de una clase regular con una propiedad de cadena pasa como se esperaba. Definitivamente es la carpeta de tiempo de ejecución que no se está comportando ... – piff

+0

Si mira el enlace de respuesta de igofed a Microsof Connect, este error es conocido y probablemente no se resolverá en la nueva versión VS. – JotaBe

Respuesta

2

Una buena pregunta esto.

Parece que está tomando el tipo de expresión en tiempo de compilación, IInheritEcho, y no busca en profundidad los miembros de las interfaces heredadas cuando busca el método para invocar dinámicamente.

e idealmente el ligante C# tiempo de ejecución para una expresión dynamic deben comportarse de la misma manera que el compilador de C# - por lo que debe ver que la interfaz IEcho es heredado por IInheritEcho y debería funcionar.

Podemos probar la hipótesis - es decir, que se trata de la tipificación estática - al hacer esto en la primera prueba:

echo = ((dynamic)echomore).EchoString(dynObject.Foo); 

Hey presto - pasa la prueba.

Así que el problema no es que el aglutinante dinámica no puede encontrar el método - es que cuando la instancia cuyo miembro está siendo invocado de forma dinámica es estático de tipos de interfaz, las interfaces heredadas no son consultados.

En mi opinión, este comportamiento es incorrecto.

Por favor, Eric Lippert ... sería agradable ...

4

You situaciones es un error documentado en Microsoft Connect

+0

Es un problema conocido. Sigue a [esta pregunta] (http://stackoverflow.com/questions/3696047/why-calling-isetdynamic-contains-compiles-but-throws-an-exception-at-runtim) que es una buena discusión sobre el tema – piff

+0

Para su información, si alguien encuentra esto de nuevo a través de Google, el juicio final de Microsoft sobre este error está "cerrado, ya que no se solucionará", el 4/6/2011 debido a que se "escapó". abucheo. :( – longda

+0

¿Y cinco años después todavía está fuera del alcance? –

Cuestiones relacionadas