映射两个相同类型的对象(不包括某些字段)的最佳方法是什么?
我之前在这里发布了我的问题,但我没有得到任何回复原因 – 我猜 – 它太通用了。 我会试着更简洁。
我有两个相同类型的对象,我想映射一些属性并排除其他属性。 我想要做的是将对象保存在缓存中并稍后使用具有特定属性的属性(字段)获取它。
我看过Automapper,但是我没有找到任何适合我的东西,所以我想要实现我自己的系统。
我创建了一个属性:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] public class FilterFieldAttribute: Attribute { }
并在我需要包含的字段上装饰了一个类:
public class OrdersViewModel : BaseViewModel { ... [FilterField] [DisplayName("Order Number:")] public string OrderNumber { get; set; } [FilterField] [DisplayName("From date:")] public DateTime FromDate { get; set; } [FilterField] [DisplayName("To date:")] public DateTime ToDate { get; set; } [DisplayName("Status:")] public int Status { get; set; } ... }
现在,我已经实现了一个负责映射的函数:
private T Map(T Source, T Destination) where T : BaseViewModel { if (Source == null) { return (Source); } FilterFieldAttribute filterAttribute; foreach (PropertyInfo propInfo in typeof(T).GetProperties()) { foreach (FilterFieldAttribute attr in propInfo.GetCustomAttributes(typeof(FilterFieldAttribute), false)) { filterAttribute = attr as FilterFieldAttribute; if (filterAttribute != null) { var value = propInfo.GetValue(Source, null); propInfo.SetValue(Destination, value, null); } } } return (Destination); }
现在,当我需要从缓存中获取我的viewmodel并仅填充标有该属性的属性时,我的代码如下所示:
viewModel = Map(myCache.Get(Key) as T, viewModel);
我不知道这是否是最好的,但这似乎是我找到的唯一方法。
任何建议将不胜感激。
使用直接reflection(如示例中)将是sloooow ; 给出一个更完整的答案是棘手的,因为它取决于你是否需要浅层克隆或深层克隆子对象。 无论哪种方式,您都应该期望这涉及一些元编程和缓存 – 使用ILGenerator或Expression。
但是,对于惰性选项,序列化可能很有用。 许多序列化程序允许您使用属性来包含/排除特定项目; 通过序列化到内存流,倒带( .Position=0
)和反序列化你应该得到你所选成员的深层副本。
以下是使用Expression
的示例:
using System; using System.ComponentModel; using System.Linq; using System.Linq.Expressions; [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] public class FilterFieldAttribute: Attribute { public static T Clone(T obj) where T : class, new() { return Cache .clone(obj); } private static class Cache where T : class, new() { public static readonly Func clone; static Cache() { var param = Expression.Parameter(typeof(T), "source"); var members = from prop in typeof(T).GetProperties() where Attribute.IsDefined(prop, typeof(FilterFieldAttribute)) select Expression.Bind(prop, Expression.Property(param, prop)); var newObj = Expression.MemberInit(Expression.New(typeof(T)), members); clone = Expression.Lambda>(newObj, param).Compile(); } } } public class OrdersViewModel { [FilterField] [DisplayName("Order Number:")] public string OrderNumber { get; set; } [FilterField] [DisplayName("From date:")] public DateTime FromDate { get; set; } [FilterField] [DisplayName("To date:")] public DateTime ToDate { get; set; } [DisplayName("Status:")] public int Status { get; set; } static void Main() { var foo = new OrdersViewModel { OrderNumber = "abc", FromDate = DateTime.Now, ToDate = DateTime.Now, Status = 1}; var bar = FilterFieldAttribute.Clone(foo); } }
听起来是一个好的开始,但你正在失去AutoMapper的这么多好处。 AutoMapper还可以处理您在此处没有的嵌套属性(当您的类包含嵌套的映射类时)。
由于AutoMapper是一个oprn源项目,我建议您使用AutoMapper源并在那里实现过滤。 事实上,这对其他人来说也是有益的。
我认为你的方法还可以。 反思有一些性能影响 – 值得考虑。
另一种高效且简单的方法可能是让BaseViewModel定义一个抽象方法:
public abstract BaseViewModel ToCacheVersion();
哪个可用于将子类转换为正确的类型。 每个子类都会处理自己的映射:
public class ViewModelX { public ViewModelX(string name, string description) { Name = name; Description = description; } ... public override BaseViewModel ToCacheVersion() { return new ViewModelX( Name, // Include the name. null // Ignore the description. ); } ... }
- 处理无效的XMLhex字符
- 循环遍历一个对象并找到not null属性
- 无法将类型’string’隐式转换为’System.Windows.Forms.TextBox’
- 如何复制与安装程序位于同一目录中的文件
- 动态关键字vs对象数据类型
- 由于PreviewMouseLeftButtonDown,Datagrid内的按钮未被触发
- HttpUtility.ParseQueryString()始终将特殊字符编码为unicode
- Visual Studio 2012 MVC构建错误:名称空间“System.Data.Entity”中不存在类型或命名空间名称“Infrastructure”
- 将DataTable分配给ViewState是一个好方法吗?