使用反射和列表的 C# 动态转换

发布于 2024-10-17 12:36:11 字数 1080 浏览 1 评论 0原文

从昨天开始,我正在解决一个问题,但我还不明白......

我有一个包含许多方法的类,并决定在运行时必须调用该方法。每个方法都会返回一个列表,其中包含来自我的 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 但行为相同。

是否可以读取方法返回值的反射类型?然后我可以使用此返回值创建一个通用列表并转换为该列表吗?这太棒了。

问候并非常感谢您的帮助! 本尼

since yesterday i'm working on a problem and i don't get it yet...

I've got a class with many Methods and decide in Runtime wich Method has to be called. Every of this Methods returns a List with Elements from my Businessobjects.

My Class looks this way:

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

So, at Invoking the Method i got a
InvalidCastException
and the Debugger told me he could not Cast from

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

to

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

I wonder why this doesn't work. I thougt if i use a List every Object could be in this List.

I've even tried it with List but same behaviour.

Is it possible to read reflective the Type of the Return-Value of a Method? And can i then create a Generic List with this Returnvalue and cast to this List? This would be wonderfull.

Greetings and many Thanks for your Help!
Benni

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

分开我的手 2024-10-24 12:36:11

显然 BO1 派生自 Object,并且您无法将 List 转换为 List。假设我们有:

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 代替。

Obviously BO1 derives from Object, and you can't cast List<Derived> to List<Base>. Suppose we have:

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

You can use IEnumerable<T> instead.

踏月而来 2024-10-24 12:36:11

如果您的行为会发生变化并在运行时确定,那么它非常适合策略模式。看看 http://www.dofactory.com/Patterns/PatternStrategy.aspx

If you have behaviour that changes and is determined at runtime, it's ideal for the Strategy pattern. Have a look at http://www.dofactory.com/Patterns/PatternStrategy.aspx

戏舞 2024-10-24 12:36:11

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

List<_> needs to be invariant to be statically type-safe. Imagine this compiled

var strlist = List<string> { "blub" };
var olist = (List<object>)strlist;

Up to this point everything is nice and dandy, but if you now tried to write to
the list like so

olist.Add(3);

the runtime would have to throw an exception as the underlying array is not an int array, but a string array. That's why it does not compile in the first place.

Note that contary to generic lists, arrays have been covariant since C# 1.0,
probably for Java compatibility. So this indeed compiles:

string[] strlist = new[] { "huhu" };
var olist = (object[])strlist;
olist[0] = 3;

... but throws an exception at runtime.

IEnumerable<out T> is covariant in T in C# 4.0 (therefore the out). Maybe this would be the more appropriate interface for your purposes.

为人所爱 2024-10-24 12:36:11

你可以使用这个:

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

You can use this :

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 });
你列表最软的妹 2024-10-24 12:36:11

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

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

You should really split your class into two different classes, that should implement same interface. Using reflaction here is not a good thing.

Or if you methdods differ only in type of input parameters, make them generic.

︶葆Ⅱㄣ 2024-10-24 12:36:11

那么唯一的解决方案是创建一个新列表..

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

Well the only solution is to create a new list..

 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!
    }
失与倦" 2024-10-24 12:36:11

我感谢所有的答案!

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

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

I appreciate all the Answers!

For your information: I've implemented the Strategy Pattern, because it fits really good to my Project.

PS: I love this community, the peoble here help you so quick and with good solutions. Thanks!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文