Динамическое приведение C # с отражением и списками - PullRequest
2 голосов
/ 16 февраля 2011

со вчерашнего дня я работаю над проблемой, но пока не понимаю ...

У меня есть класс со многими методами, и в среде исполнения я решаю, какой метод должен быть вызван. Каждый из этих методов возвращает список с элементами из моих бизнес-объектов.

Мой класс выглядит так:

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

Итак, при вызове метода я получил InvalidCastException и отладчик сказал мне, что он не может кастовать с

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

до

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

Интересно, почему это не работает? Я полагаю, если я использую Список, каждый объект может быть в этом списке.

Я даже пробовал это с List, но такое же поведение.

Можно ли считать рефлексивным тип возвращаемого значения метода? И могу ли я затем создать общий список с этим значением возврата и привести к этому списку? Это было бы замечательно.

Приветствую и большое спасибо за вашу помощь! Benni

Ответы [ 7 ]

3 голосов
/ 16 февраля 2011

Очевидно, 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> вместо.

2 голосов
/ 16 февраля 2011

Вы можете использовать это:

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 });
2 голосов
/ 16 февраля 2011

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> ковариантен в T в C # 4.0 (следовательно, out). Может быть, это будет более подходящий интерфейс для ваших целей.

2 голосов
/ 16 февраля 2011

Если у вас есть поведение, которое меняется и определяется во время выполнения, это идеально подходит для шаблона стратегии. Посмотрите на http://www.dofactory.com/Patterns/PatternStrategy.aspx

1 голос
/ 16 февраля 2011

Ну, единственное решение - создать новый список ..

 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!
    }
1 голос
/ 16 февраля 2011

Вы должны действительно разделить ваш класс на два разных класса, которые должны реализовывать один и тот же интерфейс. Использование рефлексии здесь не очень хорошая вещь.

Или, если ваши метадоды отличаются только типом входных параметров, сделайте их общими.

0 голосов
/ 16 февраля 2011

Я ценю все ответы!

К вашему сведению: я реализовал шаблон стратегии, потому что он очень хорошо подходит для моего проекта.

PS: я люблю это сообщество, люди здесь помогают вам так быстро и с хорошими решениями. Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...