基本上,我正在寻找一种将GenericList<TInput>
转换为GenericList<TOutput>
的方法,其中GenericList
是实现特定接口的任何类型的通用列表,以及类型{{ 1}}和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
,因此我无法通过正常{调用{ {1}}或通过通用IsGenericMethod=false
(无法调用method.Invoke
)。
答案 0 :(得分:2)
这不是SelectMany的全部意义吗?假设我有两个不同类型的列表,listA和listB,那么listC是一个新列表,如:
var listC = listA.SelectMany(a => listB, (a, b) => new { a.PropertyA, b.PropertyB });
你说你直到运行时才知道类型,但它们实现了特定的接口,因此你不必使用反射。所以在你的情况下,listA将是一个IEnumerable而PropertyA和PropertyB将是你的界面暴露的一些属性。
或者,如果您正在使用评论中提到的属性,则可以使用创建匿名类型的属性。
答案 1 :(得分:1)
如果我已正确理解您的问题,您应该可以使用类型转换器。但是,如果可能的TInput和TOutput列表相对较小并且遵循定义的映射,这将真正可行。使用自定义类型转换器,您可以使用标准方法CanConvertTo,CanConvertFrom,ConvertTo和ConvertFrom来实现所需的转换。您对这些方法的实现将进行必要的数据复制。
答案 2 :(得分: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
的列表转换为新列表。