我试图通过反射调用类方法。
public class A
{
public string B(IWork WorkToDo)
{
return WorkToDo.ToString();
}
}
类"Work"继承自"IWork"。
Type type = Type.GetType("A");
MethodInfo MI = type.GetMethod("B");
object X = MI.Invoke(Activator.CreateInstance(type), new object[] { new Work() });
上面这行抛出参数error.."预计IWork…而不是工作……"
如果我写
object X = MI.Invoke(Activator.CreateInstance(type), new object[] { (new Work() as IWork) });
。
我想知道为什么它不能自动推断和类型转换多态性,或者我完全错了?我们能请个定制班来修水管吗?
请帮助。
编辑
OK。抱歉你们隐瞒了真正的问题。它也适用于Array[],但在List<>…
上抛出错误。所以我的class是:
public class A
{
public string B(List<IWork> WorkToDo)
{
return WorkToDo.ToString();
}
}
Type type = Type.GetType("A");
MethodInfo MI = type.GetMethod("B");
List<Work> WL = new List<Work>(); WL.Add(new Work());
object X = MI.Invoke(Activator.CreateInstance(type), new object[] { WL });
错误是:
类型为'System.Collections.Generic.List
1[Work]' cannot be converted to type 'System.Collections.Generic.List
1[IWork]'的对象。
更新后,问题变得很明显。List<Work>
不是 List<IWork>
。List<T>
不协变,如
interface IWork { }
class Work : IWork { }
class OtherWork : IWork { }
接受List<IWork>
的方法可以很好地尝试添加new OtherWork()
,这将是一个完全合法的编译时的事情。如果方法传递了一个List<Work>
,添加OtherWork将是一个完全非法的运行时的事情,因此语言阻止你在List<IWork>
应该传递的地方传递List<Work>
。
您可能想要做的是让方法接受IEnumerable<IWork>
,这将允许您传递List<Work>
。IEnumerable<T>
是协变的(在c# 4中),因为它是只读的,所以不会对序列进行写操作或添加操作。
完整的工作示例:
namespace Foo
{
public class A
{
// note the change to the signature
public string B(IEnumerable<IWork> workToDo)
{
return workToDo.ToString();
}
static void Main()
{
var type = Type.GetType("Foo.A");
var info = type.GetMethod("B");
var list = new List<Work>();
var x = info.Invoke(Activator.CreateInstance(type), new [] { list });
}
}
public interface IWork { }
public class Work : IWork { }
}
至于为什么它对数组有效,数组方差被打破了。它允许在编译时做一些在运行时可能完全危险的事情。同样的问题可能在运行时出现,如果您有一个接受IWork[] array
的方法,并且您传递Work[]
,编译器将允许您在这种情况下这样做。然而,说array[0] = new OtherWork();
是完全合法的(在编译时),你会得到一个运行时异常。