将匿名通用列表复制到匿名数组

时间:2015-12-08 13:32:29

标签: c# arrays generics reflection anonymous

我需要复制一个匿名通用List<>到一个匿名数组。 事实是我不知道设计时的元素类型。所有必须在运行时使用反射解决。 请阅读代码中的注释以进一步解释问题。 我需要一种新方法来实现这一目标。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace MapperTestLogic
{
    public class temp
    {
        //Source is an Object with Properties of Generic Lists, Destination is an Object with Properties of type Array
        //The Property Names are allways the same
        public void Copy(object Source, object Destination) 
        {
            Type sourceType = Source.GetType();
            Type destinationType = Destination.GetType();

            foreach (PropertyInfo sourceProp in sourceType.GetProperties())
            {
                if (sourceProp.GetValue(Source, null) != null)
                {
                    PropertyInfo destProp = destinationType.GetProperty(sourceProp.Name); //Get the same Property in destination
                    Type sourceItemType;
                    Type destItemType;

                    //Destination is Array, Source inherits from IList..
                    if (destProp != null && destProp.PropertyType.IsArray && InheritsFromIList(sourceProp, out sourceItemType))
                    {
                        //..get the Source
                        var colSource = ((IEnumerable<dynamic>)sourceProp.GetValue(Source, null)).ToList();
                        var colDestination = destProp.GetValue(Destination, null);

                        //..get the Destination Element Type (They are not the same Types as in the List but they have the same name)
                        Type t = colDestination.GetType();
                        destItemType = t.GetElementType();

                        var listType = typeof(List<>);
                        var constructedListType = listType.MakeGenericType(destItemType);
                        var listInstance = (IList)Activator.CreateInstance(constructedListType); //Create a new IList-Instance of destination Element Type

                        foreach (var sourceItem in colSource)
                        {
                            //Iterate through sourcitems and create instances of destination type
                            var di = Activator.CreateInstanceFrom(destItemType.Assembly.CodeBase, destItemType.FullName);
                            var destItem = di.Unwrap();
                            di = null;

                            listInstance.Add(destItem);
                        }

                        //Create new Array Instance with the the correct Destination Elementtype in the correct Size..
                        var arrDestination = Activator.CreateInstance(t, new object[] { listInstance.Count });

                        //From here on the Code is not working properly

                        foreach(var item in listInstance)
                        {
                            arrDestination[0] = item; //Here I will copy the value but get the compiler Error: Cannot apply indexing with [] to an expression of type object
                        }

                        //I know why etc. I need now an other approach to solve my problem.



                        destProp.SetValue(Destination, arrDestination);
                    }
                }
            }
        }

        private bool InheritsFromIList(PropertyInfo sourceProp, out Type ItemType)
        {
            ItemType = typeof(NullClass);

            foreach (Type interfaceType in sourceProp.PropertyType.GetInterfaces())
            {
                if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IList<>))
                {
                    //if so, work each element of the List
                    ItemType = sourceProp.PropertyType.GetGenericArguments()[0];
                    break;
                }
            }

            if (ItemType != typeof(NullClass))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    internal class NullClass
    {
        //Helperclass for Method InheritsFromIList
    }
}

1 个答案:

答案 0 :(得分:0)

正如Rob所提到的,您可以使用Enumerable.ToArray<TSource> Method来创建匿名数组。为确保类型兼容性,您可以使用Type.IsAssignableFrom Method

public void Copy(object Source, object Destination)
{
    Type sourceType = Source.GetType();
    Type destinationType = Destination.GetType();

    foreach (PropertyInfo sourceProp in sourceType.GetProperties())
    {
        var targetProperty = destinationType.GetProperty(sourceProp.Name);
        if (targetProperty != null &&
            targetProperty.PropertyType.IsArray &&
            typeof (IList<>)
                .MakeGenericType(targetProperty.PropertyType.GetElementType())
                .IsAssignableFrom(sourceProp.PropertyType))
        {
            var closedGenericMethod =
                typeof (Enumerable).GetMethod(nameof(Enumerable.ToArray))
                    .MakeGenericMethod(targetProperty.PropertyType.GetElementType());
            var item = sourceProp.GetValue(Source, null);
            var resultArray = closedGenericMethod.Invoke(null, new[] {item});
            targetProperty.SetValue(Destination, resultArray);
        }
    }
}