将 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);
假设我有 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);