经过一些重构后,遇到了一个有趣的运行时问题,并将其归结为以下情况。
将属性从动态对象传递到已从父接口继承的接口上的方法时,运行时绑定程序无法找到该方法。
这是一个测试,用于演示失败和成功(直接在父接口类型上调用方法)
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失败。预期:其中(空)取代。实际:。 'Test.Utility.IInheritEcho'不包含'EchoString'的定义
测试#2成功。
我的问题是,我认为第一次测试应该通过的假设是正确的,还是框架中有一个根本原因,它不是?
我知道我可以通过在传入参数时转换参数来解决问题,或者在传递它们之前将它们分配给变量。我更好奇的是继承接口导致RuntimeBinder失败的原因。
答案 0 :(得分:4)
您的情况是Microsoft Connect
上记录的错误答案 1 :(得分:2)
一个很好的问题。
在查找要动态调用的方法时,它似乎在编译时采用表达式的类型IInheritEcho
,而不是深层搜索继承接口的成员。
理想情况下,dynamic
表达式的C#运行时绑定程序应该与C#编译器的行为方式相同 - 因此它应该看到IEcho
接口由IInheritEcho
继承,它应该工作
我们可以在第一次测试中测试假设 - 即它是静态类型:
echo = ((dynamic)echomore).EchoString(dynObject.Foo);
嘿presto - 测试通过。
所以问题不在于动态绑定器找不到方法 - 当动态调用其成员的实例静态类型作为接口时,不会查询继承的接口。
在我看来,这种行为是不正确的。
请Eric Lippert ......好好......