为什么此运行时动态绑定失败?

时间:2011-10-17 17:17:04

标签: c# dynamic

为什么以下测试失败?

[TestClass]
public class DynamicTests
{
    public class ListOfIntsTotaller
    {
        public float Total(List<int> list) { return list.Sum(); }
    }
    public static class TotalFormatter
    {
        public static string GetTotal(IEnumerable list, dynamic listTotaller)
        {
            //  Get a string representation of a sum
            return listTotaller.Total(list).ToString();
        }
    }
    [TestMethod]
    public void TestDynamic()
    {
        var list = new List<int> { 1, 3 };
        var totaller = new ListOfIntsTotaller();
        Assert.AreEqual("4", totaller.Total(list).ToString()); // passes 
        Assert.AreEqual("4", TotalFormatter.GetTotal(list, totaller)); // fails
    }
}

出现以下错误:

  

Test method MyTests.DynamicTests.TestDynamic threw exception:
  Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: The best overloaded method match for 'MyTests.DynamicTests.ListOfIntsTotaller.Total(System.Collections.Generic.List<int>)'
has some invalid arguments

绑定器是否应该足够聪明以使list与其基础类型List<int>匹配,从而成功绑定到GetTotal方法?

4 个答案:

答案 0 :(得分:5)

问题是list方法中的GetTotal不是List<int>

动态调用是根据您使用的变量的类型确定的,而不是它指向的对象的实际类型。方法Total需要List<int>,而不是IEnumerable

答案 1 :(得分:4)

这是因为在调用函数Total时,IEnumerable无法转换为List类型。

List implements  IList<T>, ICollection<T>, 
          IEnumerable<T>, IList, ICollection, IEnumerable

传递

IEnumerable<int>

同时总计 GetTotal 都可以解决问题。

答案 2 :(得分:2)

这是因为你无法从IEnumerable转变为List<int> 请尝试使用此行代替

public float Total(IEnumerable<int> list) { return list.Sum(); }

所以这不是你的动态失败,而是函数调用没有传入有效的参数

答案 3 :(得分:1)

这是对Guffa答案的补充(仍然完全有效)。

就像afeygin一样,我认为动态调用会检查正确的底层类型 但在我的情况下,由于缺乏信息,我没有机会修改界面。

以下是例子:

// I know that doit will be a certain type like MyDoIt but i can't know the actual type
// The only information I have is that MyDoIt is implementing IToBeDone 
public void DoIt(IToBeDone doit)
{
    // I know that _doItInstance.DoIt will expect MyDoIt but can't know the actual
    // type here so this will throw
    _doItInstance.DoIt(doit);
}

这是一个解决方法:

public void DoIt(IToBeDone doit)
{
    // this will cause that IToBeDone won't be used for type resolution but the real
    // type instead (in my case MyDoIt)
    dynamic dynDoit = doit;
    _doItInstance.DoIt(dynDoit);
}