您的位置:首页 > 移动开发

Github 开源:高效好用的对象间属性拷贝工具 升讯威 Mapper:( Sheng.Mapper)

2017-06-16 11:57 567 查看
Github 地址https://github.com/iccb1013/Sheng.Mapper
 

对象属性值映射/拷贝工具。不需要创建映射规则,不要求对象类型一致,适用于简单直接的拷贝操作,可以全属性拷贝,指定属性拷贝,排除指定的属性。拷贝包含 10 个属性的对象 10 万次,耗时 4.x 秒(普通开发机)。

 


 

+ 拷贝行为只针对 sourceObject 和 targetObject 所共有的属性
+ 在 sourceObject 和 targetObject 中的待拷贝的属性值的类型处理:如果是值类型,直接拷贝,如果是引用类型,sourceObject 中的属性的类型 必须 和 targetObject 中的属性的类型一致,或是它的派生类
+ 如果要支持类型不一致的属性自动进行类型转换,你可以在 PropertyMappingDescription 这个类中实现转换器功能
+ 拷贝行为 不会 改变 targetObject 中不需要被拷贝的属性的值
+ 你可以组合使用几个方法来从多个对象中拷贝指定的属性值到一个 targetObject

和 AutoMapper 互补,与之相比最大优势是短,平,快。不需要创建复杂的映射规则,并支持属性排除操作。

 

具体实现:

这里在具体实现上,其实并不复杂,只需对反射操作稍有了解即可,

我们通过 sourceObject 和 targetObject ,获取它们的“类型(Type)”,然后使用 Type.GetProperties() 方法,获取这个对象类型所包含的属性(Property)。

PropertyInfo[] propertyList = Type.GetProperties();
foreach (PropertyInfo property in propertyList)
{
PropertyMappingDescription propertyMappingDescription = new PropertyMappingDescription(property);

_propertyList.Add(propertyMappingDescription);
_propertyNames.Add(property.Name, propertyMappingDescription);
}


这里有另外一个细节需要留意的是,我们要把同样类型(Type)的相关信息,缓存起来,这样下次再拷贝相同类型的对象时,就无需再去反射它的 Properties。

我们通过 TypeMappingDescription 对对象的类型信息进行缓存和包装,提供我们所需要的基本操作:

public bool ContainsProperty(string name)
{
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException("TypeMappingDescription.ContainsProperty 必须指定属性名。");

return _propertyNames.ContainsKey(name);
}

public object GetValue(object obj, string propertyName)
{
if (obj == null)
throw new ArgumentNullException("指定的对象为空。");

if (obj.GetType() != this.Type)
throw new ArgumentException("指定的对象类型与缓存的对象类型不一致。");

if (_propertyNames.ContainsKey(propertyName) == false)
throw new ArgumentOutOfRangeException("指定的属性名不存在。");

PropertyMappingDescription propertyMappingDescription = (PropertyMappingDescription)_propertyNames[propertyName];
if (propertyMappingDescription.CanRead == false)
throw new InvalidOperationException("属性 " + propertyName + "不可读。");

return propertyMappingDescription.GetValue(obj);
}

public void SetValue(object obj, string propertyName, object value)
{
if (obj == null)
throw new ArgumentNullException("指定的对象为空。");

if (obj.GetType() != this.Type)
throw new ArgumentException("指定的对象类型与缓存的对象类型不一致。");

if (_propertyNames.ContainsKey(propertyName) == false)
throw new ArgumentOutOfRangeException("指定的属性名不存在。");

PropertyMappingDescription propertyMappingDescription = (PropertyMappingDescription)_propertyNames[propertyName];
if (propertyMappingDescription.CanWrite == false)
throw new InvalidOperationException("属性 " + propertyName + "只读。");

Type propertyType = propertyMappingDescription.PropertyInfo.PropertyType;
if (propertyType.IsValueType == false && value != null)
{
Type valueType = value.GetType();
if(propertyType != valueType && valueType.IsSubclassOf(propertyType) == false)
{
throw new ArgumentException("目标对象的 " + propertyName + "与 value 的类型既不一致,也不是目标类型的派生类。");
}
}

propertyMappingDescription.SetValue(obj, value);
}


 

同时我们使用 PropertyMappingDescription 对 PropertyInfo 进行封装。对 PropertyInfo 进行封装,是为了方便我们后续针对属性添加属性值的转换器,以便实现稍复杂一些的属性拷贝操作。

 

最后我们来测试一下拷贝操作:

A a = new A()
{
Name = "张三",
Age = 10,
Class = "一班",
CObject = new SubC()
{
Message = "Hello"
},
P1 = "1",
P2 = "2",
P3 = "3",
P4 = "4",
P5 = "5",
P6 = "6"
};

B b = new B();

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();

for (int i = 0; i < 100000; i++)
{
//全部属性拷贝
ShengMapper.SetValues(a, b);

//拷贝指定的属性
// ShengMapper.SetValuesWithProperties(a, b, new string[] { "Name", "Age", "P1" });

//排除指定的属性
//ShengMapper.SetValuesWithoutProperties(a, b, new string[] { "Name", "Age", "P1" });

}

stopwatch.Stop();

Console.WriteLine("对包含 10 个属性的对象的属性值拷贝 10 万次,耗时:" + stopwatch.Elapsed.ToString());

Console.ReadLine();


 

我模拟了一几个类,他们有不同类型的属性,还包括引用类型的属性我派生类。

对于包含 10 个属性的类的 10 万次属性值拷贝,在开发机上大约用了 4.x 秒。

 

完整的代码位于 Github。

https://github.com/iccb1013/Sheng.Mapper

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  .NET 开源 github c# 架构