对象属性赋值后续(集合对象的属性赋值)
(一)前言
继《对象属性之间的相互赋值 》后,关于集合对象属性的赋值,主要可以通过循环遍历集合中的对象来进行属性间的赋值。这些可以运用于不同对象之间、相关属性类似的情况。最常见的是web services与silverlight之间的对象赋值(对象之间的属性值只有一部分是需要的),这样可以减少silverlight对web services的依赖。
(二)具体实现
通过反射将源对象与目标对象之间的属性赋值。源对象的属性名、属性类型必须与目标对象的属性名、属性类型一致,并且源对象的属性必须是可读的,目标对象的属性是可写的(仅针对于需要赋值的属性来说)。具体的源代码如下:
2 {
3 private static readonly Dictionary<string, IList<PropertyMapper>> _mappers =
4 new Dictionary<string, IList<PropertyMapper>>();
5
6 public static IList<PropertyMapper> GetMapperProperties(
7 Type sourceType, Type targetType)
8 {
9 var sourceProperties = sourceType.GetProperties();
10 var targetProperties = targetType.GetProperties();
11
12 return (from s in sourceProperties
13 from t in targetProperties
14 where s.Name == t.Name && s.CanRead && t.CanWrite && s.PropertyType == t.PropertyType
15 select new PropertyMapper
16 {
17 SourceProperty = s,
18 TargetProperty = t
19 }).ToList();
20 }
21
22 public static void CopyProperties<T1, T2>(List<T1> sources, List<T2> targets) where T2:new()
23 {
24 if (sources == null || sources.Count == 0 || targets == null)
25 {
26 return;
27 }
28
29 T2 target;
30 foreach (T1 source in sources)
31 {
32 target = new T2();
33 CopyProperties(source, target);
34 targets.Add(target);
35 }
36 }
37
38 public static void CopyProperties(object source, object target)
39 {
40 if (source == null || target == null)
41 {
42 return;
43 }
44 var sourceType = source.GetType();
45 var targetType = target.GetType();
46 string key = GetMapperKey(sourceType, targetType);
47 if (!_mappers.ContainsKey(key))
48 {
49 MapperProperties(sourceType, targetType);
50 }
51
52 var mapperProperties = _mappers[key];
53
54 SetPropertityValue(source, target, mapperProperties);
55 }
56
57 private static void SetPropertityValue(object source,
58 object target, IList<PropertyMapper> mapperProperties)
59 {
60 for (int index = 0, count = mapperProperties.Count; index < count; index++)
61 {
62 var property = mapperProperties[index];
63 var sourceValue = property.SourceProperty.GetValue(source, null);
64 property.TargetProperty.SetValue(target, sourceValue, null);
65 }
66 }
67
68 protected static string GetMapperKey(Type sourceType, Type targetType)
69 {
70 return string.Format("{0}_{1}", sourceType.FullName,
71 targetType.FullName);
72 }
73
74 public static void MapperProperties(Type source, Type target)
75 {
76 if (source == null || target == null)
77 {
78 return;
79 }
80
81 string key = GetMapperKey(source, target);
82 if (_mappers.ContainsKey(key))
83 {
84 return;
85 }
86
87 var properties = GetMapperProperties(source, target);
88 _mappers.Add(key, properties);
89 }
90 }
有效的方法主要为如下2个:
(1)第22-36行CopyProperties<T1, T2>(List<T1> sources, List<T2> targets) where T2:new()
目标对象集合必须添加约束(where T2:new())---必须有默认构造函数。从如下的代码可以看出 target = new T2()必须通过实例化,才能将其添加到目标集合中。
T2 target;
30 foreach (T1 source in sources)
31 {
32 target = new T2();
33 CopyProperties(source, target);
34 targets.Add(target);
35 }
(2)CopyProperties(object source, object target)
这个方法才是最关键的,因为集合对象之间的赋值主要是通过循环该方法来赋值的。
(三)单元测试
对象集合对象之间的赋值,相关的单元测试代码如下(仅考虑了简单的对象),通过下面的测试,可以检测到集合对象属性赋值赋值后,值是相同的:
2 public void CopyPropertiesTest1()
3 {
4 List<Jasen.Core.Info> sources = new List<Core.Info>();
5 for (int index = 0; index < 10; index++)
6 {
7 sources.Add(new Jasen.Core.Info()
8 {
9 Name = "jasen",
10 CreateTime = "2011-5-13".AsDateTime(),
11 Exist = true,
12 ConflictOption = ConflictOption.OverwriteChanges,
13 Index = index
14 });
15 }
16 List<Info> targets = new List<Info>();
17 ObjectMapper.CopyProperties(sources, targets);
18 for (int index = 0, count = sources.Count; index < count; index++)
19 {
20 Assert.AreEqual(sources[index].ConflictOption, targets[index].ConflictOption);
21 Assert.AreEqual(sources[index].CreateTime, targets[index].CreateTime);
22 Assert.AreEqual(sources[index].Exist, targets[index].Exist);
23 Assert.AreEqual(sources[index].Name, targets[index].Name);
24 //Assert.AreEqual(sources[index].Index, targets[index].Index);
25 }
26 }
(四)总结
以上的代码仅仅针对于简单的属性之间的赋值,对于对象包含IList集合属性的赋值,可以将该IList再进行一次赋值即可。上文中采用字典来使性能提高,当第一次赋值的时候保存需要赋值的相关联的属性对集合。第二次的时候就直接通过键值获取该属性对,不需要再次查找相关的属性对集合。
源代码下载:Jasen.CopyObjectToObjectSample.rar