2015-12-08 3 views
0

Мне нужно скопировать анонимный общий список <> в анонимный массив. Факт в том, что я не знаю тип элемента во время разработки. Все должны быть решены с использованием отражения во время выполнения. Прочтите мои примечания в Кодексе для дальнейшего объяснения проблемы. Мне нужен новый подход, чтобы получить эту работу.Скопируйте анонимный общий список в анонимный массив

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 
    } 
} 
+0

.. Знаете ли вы о '.ToArray()'? Он работает, даже если тип элемента является анонимным. – Rob

+0

.ToArra() не работает для IList. Он работает только для списка <> Поскольку невозможно создать с Активатором Список анонимного типа I, я могу реализовать IList var listInstance = (IList) Activator.CreateInstance (builtListType); – user3401367

+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); 
     } 
    } 
} 
+0

@ thehennyy: Спасибо за ваше предложение. Это выглядит очень благоприятно. Но можете ли вы объяснить мне метод «nameof» typeof (Enumerable) .GetMethod (nameof (Enumerable.ToArray)) – user3401367

+0

Оператор [nameof] (https://msdn.microsoft.com/en-us/library/dn986596 .aspx) в этом случае гарантирует, что метод ToArray существует и будет заменен компилятором «ToArray». – thehennyy

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