对象属性赋值后续(集合对象的属性赋值)

(一)前言

继《对象属性之间的相互赋值 》后,关于集合对象属性的赋值,主要可以通过循环遍历集合中的对象来进行属性间的赋值。这些可以运用于不同对象之间、相关属性类似的情况。最常见的是web services与silverlight之间的对象赋值(对象之间的属性值只有一部分是需要的),这样可以减少silverlight对web services的依赖。

 

(二)具体实现

通过反射将源对象与目标对象之间的属性赋值。源对象的属性名、属性类型必须与目标对象的属性名、属性类型一致,并且源对象的属性必须是可读的,目标对象的属性是可写的(仅针对于需要赋值的属性来说)。具体的源代码如下:

 1     public class ObjectMapper  
 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)
这个方法才是最关键的,因为集合对象之间的赋值主要是通过循环该方法来赋值的。

 

(三)单元测试

对象集合对象之间的赋值,相关的单元测试代码如下(仅考虑了简单的对象),通过下面的测试,可以检测到集合对象属性赋值赋值后,值是相同的:

 1         [TestMethod()]
 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

 

posted @ 2011-05-13 08:33  jasen.kin  阅读(3628)  评论(17编辑  收藏  举报