从昨天开始我正在解决一个问题,但我还没有得到它......
我有一个包含许多方法的类,并在Runtime中决定必须调用Method。每个方法都返回一个包含来自我的Businessobjects的元素的列表。
My Class看起来像这样:
public class ReflectiveClass {
public List<BO1> DoSomethingWithBO1(int param){
List<BO1> list = new List<BO1>();
//....
return list;
}
public List<BO2> DoSomethingWithBO2(int param){
List<BO2> list = new List<BO2>();
//....
return list;
}
public void Process(){
//...get MethodInfo and so on
List<object> myReturnValue = (List<object>)methodInfo.Invoke(this, new object[]{param});
// here comes the Exception
}
}
所以,在Invoking the Method我得到了一个 InvalidCastException的 并且调试器告诉我他无法从
转换System.Collections.Generic.List`1[BO1]
到
System.Collections.Generic.List`1[System.Object]
我想知道为什么这不起作用。我知道如果我使用List,则每个对象都可以在此列表中。
我甚至尝试使用List但行为相同。
是否可以阅读反映方法的返回值的类型?然后我可以使用此Returnvalue创建一个通用列表并转换为此列表吗?这将是美好的。
问候和许多感谢您的帮助! 本尼
答案 0 :(得分:3)
显然BO1
来自Object
,您无法将List<Derived>
投射到List<Base>
。假设我们有:
List<Apple> apples = AListOfApples();
List<Fruit> fruits = (List<Fruit>)apples; //suppose it's valid to cast
fruits.Add(new Orange()); //Of course we can add an Orange to the list of Fruit
//Now you can see the list of Apple has an Orange in it!!
您可以改为使用IEnumerable<T>
。
答案 1 :(得分:2)
如果您的行为发生了变化并且在运行时确定,那么它是策略模式的理想选择。看看http://www.dofactory.com/Patterns/PatternStrategy.aspx
答案 2 :(得分:2)
List<_>
需要不变为静态类型安全。想象一下这个编译好的
var strlist = List<string> { "blub" };
var olist = (List<object>)strlist;
到目前为止,一切都很好,花花公子,但如果你现在试着写信 像这样的清单
olist.Add(3);
运行时必须抛出异常,因为底层数组不是int数组,而是字符串数组。这就是为什么它首先不编译。
请注意,与通用列表相比,数组自C#1.0以来一直是协变的, 可能是为了兼容Java。所以这确实编译:
string[] strlist = new[] { "huhu" };
var olist = (object[])strlist;
olist[0] = 3;
...但在运行时抛出异常。
IEnumerable<out T>
在C#4.0 T
中是协变的(因此out
)。也许这将是适合您目的的更合适的界面。
答案 3 :(得分:2)
您可以使用:
object myReturnValue = mi.Invoke(this, new object[] { });
MethodInfo miToList = typeof(Enumerable).GetMethod("ToList");
MethodInfo miListObject = miToList.MakeGenericMethod(new[] { typeof(object) });
List<object> listObject = (List<object>)miListObject.Invoke(myReturnValue, new object [] { myReturnValue });
答案 4 :(得分:1)
你应该把你的类分成两个不同的类,它们应该实现相同的接口。在这里使用reflaction不是一件好事。
或者,如果您的方法与输入参数的类型不同,请将它们设为通用。
答案 5 :(得分:1)
唯一的解决方案是创建一个新列表..
public void Process(){
//...get MethodInfo and so on
List<object> myReturnValue = new List<object>(((IList)methodInfo.Invoke(this, new object[]{param})).ToArray());
// here comes no Exception!
}
答案 6 :(得分:0)
我感谢所有答案!
供您参考:我已经实施了战略模式,因为它非常适合我的项目。
PS:我喜欢这个社区,这里的peoble帮助你如此快速和良好的解决方案。谢谢!