【问题标题】:Copy a anonymous generic List to an anonymous Array将匿名通用列表复制到匿名数组
【发布时间】:2015-12-08 13:32:28
【问题描述】:

我需要将一个匿名通用 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
    }
}

【问题讨论】:

  • ..你知道.ToArray()吗?即使元素类型是匿名类型,它也可以工作。
  • .ToArra() 不适用于 IList。它仅适用于 List 因为无法使用 Activator 创建匿名类型的 List 我只能实现 IList var listInstance = (IList)Activator.CreateInstance(constructedListType);
  • 这里的最终目标是什么 - 因为你不能声明一个匿名类型的数组,客户端将如何使用结果?
  • 它将填满目标对象

标签: c# arrays generics reflection anonymous


【解决方案1】:

正如 Rob 所说,您可以使用 Enumerable.ToArray&lt;TSource&gt; 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);
        }
    }
}

【讨论】:

  • @thehennyy:谢谢你的建议。看起来非常吉祥。但是你能解释一下 Method "nameof" typeof (Enumerable).GetMethod(nameof(Enumerable.ToArray))
  • 本例中的nameof operator确保ToArray方法存在,编译器将替换为“ToArray”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-09
  • 1970-01-01
  • 2012-11-09
  • 2014-09-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多