2012-05-10 1 views
7

일부 리팩터링 후 흥미로운 런타임 문제로 빠져 나와 다음 상황에 고정되어 있습니다.동적 매개 변수를 전달하면 Method를 호출 할 때 RuntimeBinderException이 발생합니다. Inherited interface

동적 개체의 속성을 부모 인터페이스에서 상속 된 인터페이스의 메서드로 전달할 때 런타임 바인더는 메서드를 찾을 수 없습니다. 여기

은 (상위 인터페이스 타입에 직접 메소드를 호출 할 때)

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

시험 # 1 실패 실패 및 성공 모두를 입증하는 시험이다 Assert.AreEqual 실패. 예상 : < (null)>. 실제 :. 'Test.Utility.IInheritEcho'에 'EchoString'에 대한 정의가 없습니다.

테스트 2 성공.

제 질문은 제 1 테스트가 통과해야한다는 제 가정이 맞는지 또는 그렇지 않은 프레임 워크에 근본적인 이유가 있습니까?

매개 변수를 전달하거나 매개 변수를 전달하기 전에 매개 변수를 캐스팅하여 문제를 해결할 수 있음을 알고 있습니다. 상속 된 인터페이스가 RuntimeBinder를 실패하게하는 이유에 대해 궁금해합니다. ..

+0

에 문서화 된 버그입니다. (오래된 C# 버전이지만 http://msdn.microsoft.com/en-us/library/aa664578%28VS.71%29.aspx) 오류가 발생했습니다. expando 객체가 아닌 string 속성을 가진 일반 클래스를 사용한다면 어떨까요? 상속 된 인터페이스에서 메서드를 찾습니까? (VS 테스트를 직접 해보지 마십시오.) 정적 바인딩 (컴파일 타임 바인딩)이있는 경우 동적 바인더 (런타임 바인더)에 문제가 있습니다. – JotaBe

+0

문자열 속성이있는 일반 클래스를 사용하면 예상대로 성공합니다. 그것은 확실히 행동하지 않는 런타임 바인더입니다 ... – piff

+0

Microsof Connect에 대한 igofed의 대답 링크를 보면,이 버그는 knwon이며 새로운 VS 버전에서는 해결되지 않을 것입니다. – JotaBe

답변

2

좋은 질문이 있습니다.

컴파일 타임에 IInheritEcho에서 표현식의 유형을 취하고 동적으로 호출 할 메소드를 찾을 때 상속 된 인터페이스의 구성원을 상세하게 검색하지 않는 것으로 보입니다. 따라서이 IEcho 인터페이스 IInheritEcho 상속 및 작동한다는 것을 볼 수 -

그리고 이상적으로 C# 컴파일러와 같은 방식으로 작동해야 dynamic 표현에 대한 C# 런타임 바인더

. 즉 그것은 정적 타이핑의 - -

우리는 가설을 테스트 할 수 있습니다 첫 번째 테스트에서이 작업을 수행하여이 :

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

헤이 프레스토 - 테스트가 통과한다.

동적 바인더가 메서드를 찾을 수 없다는 것이 문제가 아닙니다. 동적으로 호출되는 멤버 인 인스턴스가 인 경우 인터페이스로이 상속 된 인터페이스는 참조되지 않습니다.

제 의견으로는이 동작이 잘못되었습니다.

에릭 Lippert의이 ... 좋은주세요

...

4

당신의 상황은 완전히 맞아 Microsoft Connect

+0

알려진 문제입니다. [이 질문에] (http://stackoverflow.com/questions/3696047/why-calling-isetdynamic-contains-compiles-but-throws-an-exception-at-runtim)이 문제에 대한 좋은 토론입니다. – piff

+0

FYI, Google을 통해 다시 찾는 사람에게이 버그에 대한 Microsoft의 최종 판결은 "범위가 지정됨"으로 인해 2011 년 4 월 6 일에 "수정되지 않음으로 마감되었습니다." 우우. : ( – longda

+0

5 년 후 아직 범위를 벗어 났습니까? –

관련 문제