【问题标题】:C# Dynamic Cast with Reflection and Lists带有反射和列表的 C# 动态转换
【发布时间】:2011-02-16 08:41:09
【问题描述】:

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

我有一个包含许多方法的类,并在运行时决定必须调用哪个方法。这些方法中的每一个都从我的 Businessobjects 中返回一个包含元素的列表。

我的班级是这样的:

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
    }
}

所以,在调用方法时,我得到了一个 无效转换异常 调试器告诉我他不能从

System.Collections.Generic.List`1[BO1]

System.Collections.Generic.List`1[System.Object]

我想知道为什么这不起作用。我想如果我使用一个列表,每个对象都可以在这个列表中。

我什至用 List 尝试过,但行为相同。

是否可以读取反射方法的返回值类型?然后我可以用这个返回值创建一个通用列表并转换到这个列表吗?这将是美妙的。

您好,非常感谢您的帮助! 本尼

【问题讨论】:

    标签: c# list reflection generics


    【解决方案1】:

    显然BO1 派生自Object,您不能将List&lt;Derived&gt; 转换为List&lt;Base&gt;。假设我们有:

    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&lt;T&gt;

    【讨论】:

      【解决方案2】:

      如果您的行为发生变化并在运行时确定,那么它是策略模式的理想选择。看看http://www.dofactory.com/Patterns/PatternStrategy.aspx

      【讨论】:

        【解决方案3】:

        List&lt;_&gt; 需要保持不变才能是静态类型安全的。想象一下这个编译的

        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&lt;out T&gt; 在 C# 4.0 中的 T 中是协变的(因此是 out)。也许这将是更适合您的目的的界面。

        【讨论】:

          【解决方案4】:

          你可以用这个:

          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 });
          

          【讨论】:

            【解决方案5】:

            你真的应该把你的类分成两个不同的类,它们应该实现相同的接口。在这里使用反射不是一件好事。

            或者,如果您的方法仅在输入参数的类型上有所不同,请将它们设为通用。

            【讨论】:

            • 您好,因此将其更改为 Generic 是不可能的,因为这些方法做了完全不同的事情。
            【解决方案6】:

            唯一的解决办法是创建一个新列表..

             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!
                }
            

            【讨论】:

              【解决方案7】:

              感谢所有答案!

              供您参考:我已经实现了策略模式,因为它非常适合我的项目。

              PS:我喜欢这个社区,这里的人们可以如此快速地为您提供良好的解决方案。谢谢!

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-01-02
                • 2013-09-19
                • 2019-04-30
                • 1970-01-01
                • 1970-01-01
                • 2012-06-01
                相关资源
                最近更新 更多