将 1 class 转换为具有相同字段的另一个 class

Convert 1 class to another class with same fields

假设我有 2 个 classes(一个来自我的 entity framework,另一个是全局的,它在整个应用程序中可用,而 EF 一个不是)它们都有相同的属性和字段。除了该示例之外,是否有更简单快捷的方法将实体 class 转换为全局 class?

全球一:

 public class CompanyOwner
{
    public Guid OwnerId { get; set; }
    public string CompanyName { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
}

实体模型class

 public class dbOwner
{
    public Guid OwnerId { get; set; }
    public string CompanyName { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }
}

我现在的做法:

        CompanyOwner owner = new CompanyOwner();  
        Owner dbOwner = entities.FirstOrDefault(.....)// some LINQ
        owner.CompanyName = dbOwner.CompanyName;
        owner.Address = dbOwner.Address;
        owner.Email = dbOwner.Email;
        owner.Phone = dbOwner.Phone;

AutoMapper 是你的朋友。

来自主页

AutoMapper is an object-object mapper. Object-object mapping works by transforming an input object of one type into an output object of a different type. What makes AutoMapper interesting is that it provides some interesting conventions to take the dirty work out of figuring out how to map type A to type B. As long as type B follows AutoMapper's established convention, almost zero configuration is needed to map two types.

这是唯一的转换方式,否则您可以创建相同 class 的两个不同对象。但是,我更喜欢创建一个全局 class。它在从两个不同的表中获取数据时也很有用,那时我们只需在全局 class.

中添加字段

由于像这样的映射中有许多微小的边缘情况和特殊功能,因此建议您使用 AutoMapper 之类的库,如 gsharp

但是,为了让您了解如何构建这样的映射器,这里有一个非常简单的映射器。这会找到名称与源类型上的 属性 匹配的目标类型的所有属性(大小写不变),然后生成一个编译委托,该委托实例化目标类型的新实例(在中使用默认构造函数)在这种情况下),然后使用源实例中的值初始化属性。

这绝对是最基本的形式,但应该让您了解映射器的工作原理。然后通过分析所有构造函数并找到合适的构造函数(以支持不可变类型)来扩展它;当 属性 类型不匹配时执行类型转换操作;您添加了识别名称匹配的功能,即使命名约定不同 (my_property ~ MyProperty ~ myProperty);这样的例子还在继续。

实施:

Func<TSource, TTarget> CreateMapper<TSource, TTarget>()
    where TTarget : new()
{
    var sourceProperties = typeof(TSource)
        .GetProperties()
        .Where(x => x.CanRead);
    var targetProperties = typeof(TTarget)
        .GetProperties()
        .Where(x => x.CanWrite)
        .ToDictionary(x => x.Name, x => x, StringComparer.OrdinalIgnoreCase);

    var source = Expression.Parameter(typeof(TSource), "source");
    var target = Expression.Variable(typeof(TTarget));
    var allocate = Expression.New(typeof(TTarget));
    var assignTarget = Expression.Assign(target, allocate);

    var statements = new List<Expression>();
    statements.Add(assignTarget);

    foreach (var sourceProperty in sourceProperties)
    {
        PropertyInfo targetProperty;
        if (targetProperties.TryGetValue(sourceProperty.Name, out targetProperty))
        {
            var assignProperty = Expression.Assign(
                Expression.Property(target, targetProperty),
                Expression.Property(source, sourceProperty));
            statements.Add(assignProperty);
        }
    }

    statements.Add(target);

    var body = Expression.Block(new[] { target }, statements);

    return Expression.Lambda<Func<TSource, TTarget>>(body, source).Compile();
}

用法:

var mapper = CreateMapper<dbOwner, CompanyOwner>();

var source = new dbOwner
{
    OwnerId = Guid.NewGuid(),
    CompanyName = "My Name",
    Address = "My Address",
    Phone = "My Phone",
    Email = "My Email"
};

var mapped = mapper(source);