C#Dynamic Cast with Reflection和Lists

时间:2011-02-16 08:41:10

标签: c# list reflection generics

从昨天开始我正在解决一个问题,但我还没有得到它......

我有一个包含许多方法的类,并在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创建一个通用列表并转换为此列表吗?这将是美好的。

问候和许多感谢您的帮助! 本尼

7 个答案:

答案 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帮助你如此快速和良好的解决方案。谢谢!