(一)前言
继《对象属性之间的相互赋值 》后,关于集合对象属性的赋值,主要可以通过循环遍历集合中的对象来进行属性间的赋值。这些可以运用于不同对象之间、相关属性类似的情况。最常见的是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