我将我的问题简化为一个小程序,它说明了我在运行时收到的确切错误。
您可以将其复制粘贴到控制台应用程序中,然后亲眼看看。
using System.Collections.Generic;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
var list = new List<MyDataClass>()
{
new MyDataClass {A = 1, B = 1},
new MyDataClass {A = 3, B = 8}
};
var ops = new MyOperationsClass();
ops.ReallyGreatOperation(list, list[0]);
}
}
public class MyDataClass
{
public int A { get; set; }
public int B { get; set; }
public void AddDataPartsToEachOther()
{
var c = A + B;
A = c;
B = c;
}
}
public class MyOperationsClass
{
public void ReallyGreatOperation(object obj, object z)
{
dynamic x = obj;
if (x.Contains(z)) //<-- gets an error here..
((dynamic)z).AddDataPartsToEachOther();
}
}
}
那真正的问题是什么?
据我所知,dynamic
关键字可以用作通配符,如果存在方法,它将被调用而没有问题。那么为什么在这种情况下它不适合我?
现在,我知道我可以通过这样做来改变它:
public class MyOperationsClass
{
public void ReallyGreatOperation(object obj, object z)
{
dynamic x = obj;
// if (x.Contains(z)) //<-- gets an error here..
// ((dynamic)z).AddDataPartsToEachOther();
if (x.GetType().GetMethod("Contains").Invoke(obj, new[] {z}))
((dynamic)z).AddDataPartsToEachOther();
}
}
但正如我所说 - 我希望理解为什么更“自然”的方式不起作用..因为如果我这样做是第二种方式别无选择 - 我没有看到{{1再用语言了。
收到的实际错误:
System.Core.dll中发生未处理的“Microsoft.CSharp.RuntimeBinder.RuntimeBinderException”异常
附加信息:'System.Collections.Generic.List.Contains(ConsoleApplication5.MyDataClass)'的最佳重载方法匹配有一些无效的参数
对于那些可能发现它相关的人,我添加了一段实际代码:
dynamic
感谢。
答案 0 :(得分:2)
而不是
if (x.Contains(z))
您需要将z
投射到dynamic
:
if (x.Contains((dynamic)z))
有关为何需要这些内容的详细信息,请参阅此处:Method not being resolved for dynamic generic type,我认为这个问题是重复的。
那就是说,使用dynamic
通常是糟糕的设计。使用泛型和/或接口通常有更好的方法。
答案 1 :(得分:1)
您将函数参数定义为对象,如果将参数更改为动态参数,则可以使用:
public void ReallyGreatOperation(dynamic obj, dynamic z)
{
if (obj.Contains(z))
z.AddDataPartsToEachOther();
}
这是一个非常小的测试程序:
class Program
{
static bool test(dynamic d, dynamic c)
{
return d.Contains(c);
}
static void Main(string[] args)
{
Console.WriteLine(test(new List<string>(), "not found"));
}
}
答案 2 :(得分:0)
使用as运算符,可能要检查x是否为null。
public class MyOperationsClass
{
public void ReallyGreatOperation(object obj, object z)
{
List<MyDataClass> x = obj as List<MyDataClass>;
if (x.Contains(z))
((dynamic)z).AddDataPartsToEachOther();
}
}
修改强> 另一种方法是将对象转换为IList。
public class MyOperationsClass
{
public void ReallyGreatOperation(object obj, object z)
{
IList list = obj as IList;
if (list.Contains(z))
((dynamic)z).AddDataPartsToEachOther();
}
}