2009-11-17 2 views
1

По сути, я ищу способ преобразования GenericList<TInput> в GenericList<TOutput>, где GenericList - это общий список любого типа, который реализует конкретный тип интерфейс, а типы TInput и TOutput известны только во время работы.Преобразование общего списка одного типа в другой тип, где типы известны только во время выполнения

Ниже приведен фрагмент класса и метода, который может выполнять эту операцию, где TInput и TOutput поставляются во время компиляции.

// -------------------------------------------------------------------------------- 
/// <summary>This class is an example snippet for transforming generic lists of different types.</summary> 
/// 
/// <remarks></remarks> 
// -------------------------------------------------------------------------------- 
public abstract class GenericListHelper<TInput, TOutput> 
    where TInput : IGenericObject, new() 
    where TOutput : IGenericObject, new() 
{ 

    // -------------------------------------------------------------------------------- 
    /// <summary>This method takes in a generic list of an input type 
    /// and transforms it a list of the output type.</summary> 
    /// 
    /// <param name="inputGenericList">The input list to transform to this list.</param> 
    /// <param name="filterElements">Field and property values to exclude from transform.</param> 
    // -------------------------------------------------------------------------------- 
    public static GenericList<TOutput> CreateList(GenericList<TInput> inputGenericList, NameObjectCollection filterElements) 
    { 
    if (inputGenericList != null) 
    { 
    GenericList<TOutput> outputGenericList = new GenericList<TOutput>(); 
    foreach (TInput loopItem in inputGenericList) 
    { 
    TOutput newItem = new TOutput(); 
    DataTransformHelper.TransformDataFromObject(loopItem, newItem, filterElements); 
    outputGenericList.Add(newItem); 
    } 
    return outputGenericList; 
    } 
    return null; 
    } 
} 

Есть ли способ сделать что-то вдоль этих линий, где TInput и TOutput могут быть поставлены во время выполнения?

Использование отражения в той или иной форме, кажется, путь к нему.

Сначала я попытался создать конструктор для GenericList<TInput>, который будет принимать список типов TOutput в качестве параметра (тогда я мог бы назвать Activator.CreateInstance, чтобы получить новый список).

В качестве альтернативы, я пытался вызова выше метод посредством отражения, но так как этот метод попадает ContainsGenericParameters=true и помечен как IsGenericMethod=false, я не смог вызвать метод, либо через обычный method.Invoke или через общий method.Invoke (не в состоянии для звонка MakeGenericMethod).

+0

Это C#? Как добавить тег C#? – sellibitze

+0

Что вы на земле делаете? Что случилось с IList ? – mcintyre321

+0

Я отмечен как C#. Не уверен, что вы подразумеваете под «что не так с IList . В моем случае элементы« GenericList »и« IGenericObject », которые они содержат, должны делать кучу других вещей для поддержки моих конкретных корпоративных требований. Скажем, например, у меня есть Клиенты и клиенты имеют заказы. В общей системе Domain A имеет клиентов, а заказы и домен B имеют клиентов и ордеров, в основном похожих, но не идентичных домену A. Хотите иметь возможность преобразовывать клиентов и их заказы между этими доменами и в каждом домене клиенты и заказы строго типизированы. –

ответ

2

Разве это не то, что SelectMany это все? Скажем, у меня есть два списка различных типов, lišta и LISTB, затем listC новый список, как:

var listC = listA.SelectMany(a => listB, (a, b) => new { a.PropertyA, b.PropertyB }); 

Вы сказали, что вы не знаете типы до времени выполнения, но что они реализуют определенный интерфейс, так вам не нужно использовать рефлексию. Таким образом, в вашем случае listA будет IEnumerable, а PropertyA и PropertyB - это некоторые свойства, которые предоставляет ваш интерфейс.

Или, если вы используете атрибуты, как вы упомянули в комментарии, вы можете использовать то, где создается анонимный тип.

+0

Спасибо, Ричард. d, чтобы играть с Linq больше, и это было бы мощным способом выполнения преобразований, когда свойства для преобразования известны. Мне нужно будет изучить, как применить что-то подобное, когда свойства для преобразования определяются путем сопоставления значений пользовательских атрибутов. Это может быть вопрос, который я выложу позже! –

1

Если я правильно понял вашу проблему, вы сможете использовать Преобразователи типов. Однако это будет действительно реально, если списки возможных TInput и TOutput относительно малы и следуют определенному отображению. Используя собственный конвертер типов, вы можете использовать стандартные методы CanConvertTo, CanConvertFrom, ConvertTo и ConvertFrom для достижения необходимых преобразований. Ваши реализации этих методов сделают необходимое копирование данных.

Заканчивать примеру, How to: Implement a Type Converter

+0

Спасибо. В моем случае TInput и TOutput представляют собой иерархические объекты предприятия, которые со временем будут расти (сотнями). Как конкретные преобразования должны быть выполнены с помощью пользовательских атрибуты на каждом из объектов предприятия. Я пытаюсь сохранить этот отдельный фрагмент кода независимым. –

0

В процессе постановки этого вопроса я думаю, что я ответил на свой вопрос (с помощью некоторых других сообщений здесь), но я думал, что все равно выброшу его.

Ниже приведен фрагмент некоторых конструкторов для GenericList, чтобы помочь с преобразованием (статический метод выше не используется в этом процессе).

// -------------------------------------------------------------------------------- 
/// <summary>This class is used for strongly typed sortable lists of generic 
/// objects (such as data access or business objects).</summary> 
/// 
/// <remarks></remarks> 
// -------------------------------------------------------------------------------- 
public class GenericList<T> : IGenericList<T> 
      where T : IGenericObject, new() 
{ 

    // -------------------------------------------------------------------------------- 
    /// <summary>Base constructor.</summary> 
    // -------------------------------------------------------------------------------- 
    public GenericList() 
    { 
    } 

    // -------------------------------------------------------------------------------- 
    /// <summary>This constructor takes in a generic list of the same 
    /// type and transforms it to this list.</summary> 
    /// 
    /// <param name="inputGenericList">The input list to transform to this list.</param> 
    /// <param name="filterElements">Field and property values to exclude from transform.</param> 
    // -------------------------------------------------------------------------------- 
    public GenericList(GenericList<T> inputGenericList, NameObjectCollection filterElements) 
    { 
    if (inputGenericList != null) 
    { 
    foreach (T loopItem in inputGenericList) 
    { 
    T newItem = new T(); 
    DataTransformHelper.TransformDataFromObject(loopItem, newItem, filterElements); 
    Add(newItem); 
    } 
    } 
    } 

    // -------------------------------------------------------------------------------- 
    /// <summary>This constructor takes in a generic list of another 
    /// type and transforms it to this list.</summary> 
    /// 
    /// <param name="inputListElementType">The type of element to be found in the input list.</param> 
    /// <param name="inputGenericList">The input list to transform to this list.</param> 
    /// <param name="filterElements">Field and property values to exclude from transform.</param> 
    // -------------------------------------------------------------------------------- 
    public GenericList(Type inputListElementType, object inputGenericList, NameObjectCollection filterElements) 
    { 
    if (inputGenericList != null) 
    { 
    Type inputListType = typeof(GenericList<>); 
    Type combinedType = inputListType.MakeGenericType(inputListElementType); 
    IList elements = (IList) Activator.CreateInstance(combinedType, inputGenericList, filterElements); 
    foreach (IGenericObject loopItem in elements) 
    { 
    T newItem = new T(); 
    DataTransformHelper.TransformDataFromObject(loopItem, newItem, filterElements); 
    Add(newItem); 
    } 
    } 
    } 
} 

Таким образом, вызывающий код вызывает Activator.CreateInstance создать экземпляр GenericList<TOutput>, вызывая конструктор выше, который принимает тип TInput и список типов TInput в качестве объекта.Этот конструктор вызывает другой конструктор для создания экземпляра GenericList<TInput>. Теперь исходный конструктор может использовать список типов TInput для преобразования в новый список.

Смежные вопросы