Преобразуйте список <DerivedClass> для списка <базовый класс>

Вот решение, что я думаю, лучше, чем кто-либо отправленный до сих пор:

public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

Причины, почему это - улучшение:

  • Безопасный с начальными нулями (в отличие от BigInteger) и с отрицательными значениями байта (в отличие от Byte.parseByte)

  • не преобразовывает Строку в char[] или создает объекты StringBuilder и Строки для каждого байта.

  • зависимости библиотеки No, которые не могут быть доступны

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

162
задан Bedasso 17 November 2014 в 21:13
поделиться

4 ответа

Чтобы выполнить эту работу, нужно перебирать список и приводить элементы. Это можно сделать с помощью ConvertAll:

List<A> listOfA = new List<C>().ConvertAll(x => (A)x);

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

List<A> listOfA = new List<C>().Cast<A>().ToList();
213
ответ дан 23 November 2019 в 21:20
поделиться

Прежде всего, прекратите использовать непонятные имена классов, такие как A, B, C. Используйте Animal, Mammal, Giraffe или Food, Fruit, Orange или что-то еще, где взаимосвязь ясна .

Тогда ваш вопрос: «Почему я не могу назначить список жирафов переменной типа list of animal, если я могу назначить жирафа переменной типа animal?»

Ответ: предположим, вы мог. Что же тогда может пойти не так?

Что ж, вы можете добавить Тигра в список животных. Предположим, мы позволяем вам поместить список жирафов в переменную, которая содержит список животных. Затем вы пытаетесь добавить в этот список тигра. Что происходит? Хотите, чтобы в списке жирафов был тигр? Вы хотите крушение? или вы хотите, чтобы компилятор защитил вас от сбоя, в первую очередь сделав присвоение незаконным?

Мы выбираем последнее.

Этот вид преобразования называется «ковариантным» преобразованием. В C # 4 мы позволим вам выполнять ковариантные преобразования для интерфейсов и делегатов , когда известно, что преобразование всегда безопасно . См. Подробности в статьях моего блога о ковариации и контравариантности. (На этой неделе в понедельник и четверг будет новый доклад по этой теме.)

156
ответ дан 23 November 2019 в 21:20
поделиться

Что касается того, почему это не работает, может быть полезно понять ковариацию и контравариантность .

Просто чтобы показать, почему это не должно работают, вот изменение предоставленного вами кода:

void DoesThisWork()
{
     List<C> DerivedList = new List<C>();
     List<A> BaseList = DerivedList;
     BaseList.Add(new B());

     C FirstItem = DerivedList.First();
}

Должно ли это работать? Первый элемент в списке имеет тип «B», но тип элемента DerivedList - C.

Теперь предположим, что мы действительно просто хотим создать общую функцию, которая работает со списком некоторого типа, который реализует A , но нас не волнует, какой это тип:

void ThisWorks<T>(List<T> GenericList) where T:A
{

}

void Test()
{
     ThisWorks(new List<B>());
     ThisWorks(new List<C>());
}
24
ответ дан 23 November 2019 в 21:20
поделиться

Потому что C # не поддерживает этот тип наследования преобразования в настоящий момент .

0
ответ дан 23 November 2019 в 21:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: