如何合并两个对象,覆盖空值

时间:2021-06-29 19:45:05

标签: c#

我有两个类 Book 的对象。是否可以合并两个覆盖空值的对象?

图书模型:

public string Author {get; set}
public string Title {get; set}
public string EAN {get; set}

第一本书数据:

Book.Author -> "Adam Wróbel"
Book.Title -> "StackOverflow Book"
Book.EAN-> "777777777"

第二本书数据:

Book.Author -> null
Book.Title -> "StackOverflow Book v2"
Book.EAN-> null

是否可以将这两个对象组合起来得到这样的结果?

Book.Author -> "Adam Wróbel" (data from first book)
Book.Title -> "StackOverflow Book v2" (data from second book)
Book.EAN-> "777777777" (data from first book)

P.S.我知道我可以通过检查语句是否不为空并分配给另一个对象来比较每个字段。但是,这似乎是解决此问题的一种相当有限的方法。

3 个答案:

答案 0 :(得分:2)

您可以尝试使用 Automapper 并将其设置为忽略自映射的空值:

var config = new MapperConfiguration(cfg => cfg.CreateMap<Book, Book>()
    .ForAllMembers(opts => opts.Condition((src, dest, member) => member != null)));
var mapper = config.CreateMapper();
var target = new Book
{
    Author = "1",
    Title = "1",
    EAN = "1"
};
var source = new Book
{
    Title = "2"
};
var book = mapper.Map(source, target);
Console.WriteLine($"{book.Author}-{book.Title}-{book.EAN}"); // prints "1-2-1"

答案 1 :(得分:1)

抱歉,c# 中没有内置任何东西可以做到这一点。您的选择是:

  • 手动比较和分配每个字段
  • 使用反射自动比较和分配每个字段
  • 寻找适合您的图书馆

对不起,我不知道有任何图书馆可以做到这一点。也许是 Automapper?

答案 2 :(得分:1)

最好的方法是简单地编写手动映射器。但是,如果您希望在不涉及构造函数的每个简单 POCO 情况下为您执行此操作,以下将使用反射:

  • 创建一个新的输出对象
  • 如果值不为空,则映射覆盖属性
  • 如果覆盖道具值为空,则映射基础道具
  • 并返回克隆的对象
public static class Merger
{
    public static T CloneAndMerge<T>(T baseObject, T overrideObject) where T : new()
    {
        var t = typeof(T);
        var publicProperties = t.GetProperties();
        
        var output = new T();
        
        foreach (var propInfo in publicProperties)
        {
            var overrideValue = propInfo.GetValue(overrideObject);
            var defaultValue = !propInfo.PropertyType.IsValueType 
                ? null 
                : Activator.CreateInstance(propInfo.PropertyType);
            if (overrideValue == defaultValue)
            {
                propInfo.SetValue(output, propInfo.GetValue(baseObject));   
            }
            else 
            {
                propInfo.SetValue(output, overrideValue);
            }
        }
        
        return output;
    }
}

请注意,这里没有优化或缓存。我不建议将它用于生产代码,但它是完成您所寻找的内容的一种简单方法。