我一直希望通过指定一个基本数据模型来提高我的应用程序的可扩展性,我打算将其作为容器,以便发送到另一个应用程序的数据始终具有正确的结构。
然而,我希望将来能够轻松地从XML和数据库等源加载数据,所以我想知道如何将一个对象的值复制到基础数据模型对象,在那里,从中复制值的对象可能不具有相同的结构(所以我主要只想匹配属性名)。
以下是我尝试过的:
public Dictionary<string, object> ObjectValues(object source)
{
if(source == null)
return null;
Dictionary<string, object> properties = new Dictionary<string, object>();
foreach (PropertyInfo propInfo in source.GetType().GetProperties())
{
try
{
object value = propInfo.GetValue(source, null);
properties.Add(propInfo.Name, value);
if (!value.GetType().IsPrimitive && !value.GetType().IsValueType)
{
Dictionary<string, object> internalProperties = ProxyValues(value);
if (internalProperties != null)
foreach (KeyValuePair<string, object> internalProp in internalProperties)
properties.Add(String.Format("{0}.{1}", propInfo.Name, internalProp.Key), internalProp.Value);
}
}
catch (TargetParameterCountException) { }
}
return properties;
}
谢谢,亚历克斯。
如果我正确理解你的问题,你可能想看看AutoMapper 之类的东西
您设置的配置:
Mapper.CreateMap<TypeA, TypeB>().ForMember(dest => dest.PropB, opt => opt.MapFrom(src => src.PropA));
这将创建从TypeA到TypeB的映射,其中属性PropA将复制到PropB。然后当你想使用映射:
TypeA a = new TypeA();
TypeB b = new TypeB();
Mapper.Map(a, b);
映射配置甚至可以使用自定义解析器,所以如果您想在复制时进行复杂的工作,可以。
还有ValueInjecter,有些人更喜欢它而不是AutoMap
尝试AutoMapper。它映射具有匹配属性名称的不同类型,还具有几种接受表达式来自定义映射的方法
你走在了正确的轨道上。您可以使用扩展方法来扩展带有merge
函数的基类型object
。这类事情对你自己来说是相对琐碎的。这是我使用的一个:
/// <summary>
/// Merges the equivalent properties from the source to this object.
/// </summary>
/// <typeparam name="T">Any reference type.</typeparam>
/// <param name="destination">This object, which receives the values.</param>
/// <param name="source">The source object that the values are taken from.</param>
public static void MergeFrom<T>(this object destination, T source)
{
Type destinationType = destination.GetType();
PropertyInfo[] propertyInfos = source.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var propertyInfo in propertyInfos)
{
PropertyInfo destinationPropertyInfo = destinationType.GetProperty(propertyInfo.Name, BindingFlags.Public | BindingFlags.Instance);
if (destinationPropertyInfo != null)
{
if (destinationPropertyInfo.CanWrite && propertyInfo.CanRead && (destinationPropertyInfo.PropertyType == propertyInfo.PropertyType))
{
object o = propertyInfo.GetValue(source, null);
destinationPropertyInfo.SetValue(destination, o, null);
}
}
}
}
使用它很简单:
obj1.MergeFrom(obj2);
将仅使用等效的属性名称和类型将类似的属性从obj2
合并回obj1
。注意缺乏异常处理——这是故意的,如果它失败了,那么我想知道它,而不是处理和接受异常。
您也可以将这个概念直接作为MergeFrom
或LoadFrom
放在Dictionary<string, object>
上,扩展方法为您提供了相当大的灵活性。