【问题标题】:Merge 2 Classes dynamically动态合并 2 个类
【发布时间】:2014-01-21 09:21:45
【问题描述】:

我有两个实现相同接口的类。这两个类中的一个具有比另一个更多的属性。现在我正在寻找一种解决方案,以在较大的属性中填充较少的属性。

实际上我可能会使用手动映射器。我知道,但这必须适用于调用此函数的每个类。我已经读到lambda expression 可能是我的解决方案,但我不知道如何为每个接口/类通用和动态地编写它。

我的问题是不要创建新实例,而是使用现有实例。有人有想法吗?

【问题讨论】:

  • 使用反射来遍历“小”类型的属性。对于每一个,在“大”类型上找到具有相同名称的属性。从大类型的实例中读取,并写入小类型的新实例。

标签: c# .net generics lambda func


【解决方案1】:

如果您不介意使用第三方工具,AutoMapper 做得很好。

示例取自 AutoMapper 文档:

Mapper.CreateMap<Order, OrderDto>();
OrderDto dto = Mapper.Map<OrderDto>(order);

【讨论】:

    【解决方案2】:

    如果您介意使用第三方工具,可以使用此 sn-p 并根据需要进行调整:

    public B Convert<A, B>(A element) where B : A, new()
    {
        //get the interface's properties that implement both a getter and a setter
        IEnumerable<PropertyInfo> properties = typeof(A)
            .GetProperties()
            .Where(property => property.CanRead && property.CanWrite).ToList();
    
        //create new object
        B b = new B();
    
        //copy the property values to the new object
        foreach (var property in properties)
        {
            //read value
            object value = property.GetValue(element);
    
            //set value
            property.SetValue(b, value);
        }
    
        return b;
    }
    

    【讨论】:

    • 例如,如果B 实际上不是从A 派生的,那么他可以保留属性的名称并检查其他类型是否也具有该名称的属性。
    • @JeppeStigNielsen 这是真的。正如 OP 所指出的,该代码假定两个类都实现了相同的接口。根据具体的用例,可以添加进一步的验证。
    • 或:public void Copy&lt;T&gt;(T from, T to) where T : class { /*get the interface's properties that implement both a getter and a setter*/ IEnumerable&lt;PropertyInfo&gt; properties = typeof(T) .GetProperties() .Where(property =&gt; property.CanRead &amp;&amp; property.CanWrite).ToList(); /*copy the property values to the new object*/ foreach (var property in properties) { /*read value*/ object value = property.GetValue(from); /*set value*/ property.SetValue(to, value); } }。像这样使用:var b = new B(); Copy&lt;ITheInterface&gt;(element, b);
    【解决方案3】:
    public static void BusinessObjectConverter<TTarget, TSource>(this TTarget target, TSource source)
        {
            //Lesen aller Properties auf der ersten Ebene
            var targetProperties = typeof(TTarget)
                .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                .Where(prop => prop.CanWrite);
    
            //Lesen aller Properties auf der ersten Ebene
            var sourceProperties = typeof(TTarget)
                .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                .Where(prop => prop.CanWrite);
    
            //Loop durch alle Properties
            foreach (var item in targetProperties.Intersect(sourceProperties))
            {
                //Leere Werte duerfen nicht geschrieben werden
                if (!string.IsNullOrEmpty(source.GetType().GetProperty(item.Name).GetValue(source, null).ToString()))
                {
                    //Befuellen der Properties im Zielobjekt
                    item.SetValue(target, ValueConverter.ConvertValue(
                        source.GetType().GetProperty(item.Name).GetValue(source, null),
                        item.PropertyType),
                        null);
                }
            }
        }
    

    【讨论】:

    • 这对我有用...它扩展了对象,我可以更新字段以写入数据库。
    【解决方案4】:

    由于代表人数少,我无法添加 cmets,因此必须发布答案。

    从 Automapper 的答案开始,手动创建映射可能会很痛苦。为了动态地做到这一点,我使用:

    TDestination destination = new TDestination();            
    AutoMapper.Mapper.Map<TSource, TDestination>(source, destination, opts => opts.CreateMissingTypeMaps = true);
    

    您需要记住的只是确保属性名称匹配

    【讨论】:

      猜你喜欢
      • 2017-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-21
      • 1970-01-01
      • 1970-01-01
      • 2016-07-20
      • 1970-01-01
      相关资源
      最近更新 更多