简体   繁体   English

使用反射来投射IList <Interface> 列出 <T>

[英]Using reflection to cast an IList<Interface> to List<T>

I am working on a WCF service and I have run into a bit of a snag mapping my entities to my DTO. 我正在使用WCF服务,但遇到了将实体映射到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: 这一切都非常简单:DTO.Order是我从端点和Entities返回的内容。Order是我内部在使用(我使用DI / IOC)进行业务逻辑,数据操作等的内容。由于我的业务层返回了类型从Entities命名空间返回,但是端点从DTO命名空间返回类型,我写了一个小的映射方法,它将采用一种类型并将其映射到另一种类型,如下所示:

 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. 其中Entities.DealerOrder表示包含数据的实例化对象。

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. 一切工作正常,直到获得IList类型的属性,而且我对如何将IList转换为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. 如果情况变得更糟,我可以在每个DTO上放置一个静态方法,该方法将接受源类型作为参数并返回DTO的实例,但是我想避免必须手动将字段从Entity映射到DTO如果可能的话。

Any help is greatly appreciated. 任何帮助是极大的赞赏。

  1. You can use targetProp.GetGenericArguments()[0]; 您可以使用targetProp.GetGenericArguments()[0]; to get the type of item you want to map your collection content to. 获取您想要将收藏内容映射到的项目类型。
  2. You can use Activator.CreateInstance to create List<T> with T known at runtime at not at compile time. 您可以使用Activator.CreateInstance来创建List<T>其中在运行时而不是编译时就知道T
  3. You can use Activator.CreateInstance to create instance of the type you want to map to. 您可以使用Activator.CreateInstance创建要映射到的类型的实例。
  4. You can't rely on type inference when calling MapObject anymore. 调用MapObject时,您不能再依赖类型推断了。 You need to create proper generic method via reflection here too, and call it. 您也需要通过反射来创建适当的泛型方法,然后调用它。
  5. You can't simply call Add on the list, because you don't know what kind of list it is. 您不能简单地在列表上调用“ Add ”,因为您不知道列表是哪种类型。 You can cast it to ICollection and call Add on it instead. 您可以将其ICollectionICollection然后调用Add

Can't you just use something like AutoMapper ? 您不能只使用AutoMapper之类的东西吗? Those are problems people already solved, why don't you use their work? 这些是人们已经解决的问题,您为什么不使用他们的工作呢?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM