mardi 17 novembre 2015

Using reflection to cast an IList

I am working on a WCF service and I have run into a bit of a snag mapping my entities to my DTO. Consider the following

 namespace Foo.Entities
 {
      public class Order : IOrder
      {
          public string Name { get;set; }
          public string Address { get;set; }
          public IList<ILocation> Locations { get;set; }
      }
 }

 namespace Foo.DTO
 {
      [DataContract]
      public class Order 
      {
          [DataMember]
          public string Name { get;set; }
          [DataMember]
          public string Address { get;set; }
          [DataMember]
          public List<Location> Locations { get;set; }
      }
 }

This is all very straightforward: DTO.Order is what I am returning from my endpoint and Entities.Order is what I am using internally (I am using DI / IOC) for business logic, data operations, etc. Since my business layer returns types from the Entities namespace, but the endpoint returns types from the DTO namespace I wrote a small mapping method that will take one type and map it to another type like so:

 public TTarget MapObject<TSource, TTarget>(TSource source, TTarget target)
            where TSource : class
            where TTarget : class
        {
            foreach (var prop in source.GetType().GetProperties())
            {
                var targetProp = target.GetType().GetProperty(prop.Name, BindingFlags.Public | BindingFlags.Instance);
                if(targetProp == null || !targetProp.CanWrite) continue;

                if (prop.PropertyType.GetGenericTypeDefinition() == typeof (IList<>))
                {
                    ??
                }
                else{ targetProp.SetValue(target, prop.GetValue(source)); }
            }

            return target;
        }

I then call this method like so:

factory.MapObject(Entities.DealerOrder, new GTO.DealerOrder())

where Entities.DealerOrder represents an instantiated object that contains data.

Everything works fine until I get to the property of type IList and I am at a loss at how to convert the IList to List. I know what needs to happen but all of the documentation I have read thus far hasn't pointed me in the right direction.

The pseudo is

if (prop.PropertyType.GetGenericTypeDefinition() == typeof (IList<>))
{
    var lst = new List<type of targetProp>()
    foreach(var val in prop.GetValue())
    {
        var item = new Location() (I have to figure out this initialization based on the List type of targetProp.  In this case it would be List<Location>)
         var retval = MapObject(val, item);
         lst.Add(retval);
    }
    targetProp.SetValue(target, lst);
}

I am not sure if what I want to do is even possible. I know that Generics and Reflection don't mix well so if there is a solution it might be overly complex for what I am really trying to accomplish. If worse comes to worse I can put a static method on each of my DTO's that will accept the source type as a parameter and return an instance of the DTO, but I want to avoid having to manually map the fields from the Entity to the DTO if at all possible.

Any help is greatly appreciated.





Aucun commentaire:

Enregistrer un commentaire