Reputation: 1283
Why does the following test fail?
[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
}
}
With the following error:
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
Shouldn't the binder be smart enough to match list
to its underlying type of List<int>
and thus successfully bind to the GetTotal
method?
Upvotes: 5
Views: 7534
Reputation: 8787
That's an addition to Guffa's answer (which is still completely valid).
Like afeygin I thought that a dynamic call would check the right underlying type.
But in my situation I had no chance to modify the interface because of the lack of information.
Here's the example:
// 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);
}
Here's a workaround:
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);
}
Upvotes: 1
Reputation: 1802
It is because while calling the function Total, IEnumerable cannot be converted to a type of List.
List implements IList<T>, ICollection<T>,
IEnumerable<T>, IList, ICollection, IEnumerable
passing
IEnumerable<int>
to both Total and GetTotal would do the trick.
Upvotes: 4
Reputation: 700152
The problem is that list
in the GetTotal
method is not a List<int>
.
The dynamic call is determined based on the type of the variable that you use, not the actual type of the object that it's pointing to. The method Total
takes a List<int>
, not an IEnumerable
.
Upvotes: 5
Reputation: 12670
it's the fact that you can't cast from IEnumerable
to List<int>
Try it with this line instead
public float Total(IEnumerable<int> list) { return list.Sum(); }
so it's not your dynamic failing, it's the function call not passing in valid arguments
Upvotes: 2