13
13
using AutoMapper ;
14
14
15
15
namespace LinkIt . AutoMapperExtensions
16
- { public class LinkSourceMapper < TLinkedSource , TDestination >
16
+ {
17
+ public class LinkSourceMapper < TLinkedSource , TDestination >
17
18
{
18
19
private const string ModelPropertyName = "Model" ;
19
20
private const string ContextualizationPropertyName = "Contextualization" ;
20
- private List < PropertyInfo > _contextualizationProperties ;
21
- private List < PropertyInfo > _destinationProperties ;
22
21
23
- private List < PropertyInfo > _modelProperties ;
24
- private readonly PropertyNameComparer _propertyNameComparer ;
25
- private List < PropertyInfo > _referenceProperties ;
22
+ private static readonly Type LinkedSourceType = typeof ( TLinkedSource ) ;
26
23
27
- public IMappingExpression < TLinkedSource , TDestination > MapLinkedSource ( IMappingExpression < TLinkedSource , TDestination > expression )
28
- {
29
- MapModelProperties ( expression ) ;
30
- MapContextualizedModelProperties ( expression ) ;
31
- MapPropertiesAddedInContextualization ( expression ) ;
32
-
33
- return expression ;
34
- }
35
-
36
- private void MapModelProperties ( IMappingExpression < TLinkedSource , TDestination > expression )
37
- {
38
- var modelPropertiesToMap = _modelProperties
39
- . Intersect ( _destinationProperties , _propertyNameComparer )
40
- . Except ( _referenceProperties , _propertyNameComparer )
41
- . Except ( _contextualizationProperties , _propertyNameComparer ) ;
42
-
43
- MapNestedProperties ( ModelPropertyName , modelPropertiesToMap , expression ) ;
44
- }
45
-
46
- private void MapContextualizedModelProperties ( IMappingExpression < TLinkedSource , TDestination > expression )
47
- {
48
- var contextualizedModelPropertiesToMap = _modelProperties
49
- . Intersect ( _destinationProperties , _propertyNameComparer )
50
- . Intersect ( _contextualizationProperties , _propertyNameComparer )
51
- . Except ( _referenceProperties , _propertyNameComparer ) ;
52
-
53
- MapContextualizedProperties ( contextualizedModelPropertiesToMap , expression ) ;
54
- }
55
-
56
- private void MapPropertiesAddedInContextualization ( IMappingExpression < TLinkedSource , TDestination > expression )
57
- {
58
- var propertiesAddedInContextualization = _contextualizationProperties
59
- . Intersect ( _destinationProperties , _propertyNameComparer )
60
- . Except ( _referenceProperties , _propertyNameComparer )
61
- . Except ( _modelProperties , _propertyNameComparer ) ;
24
+ private readonly PropertyNameComparer _propertyNameComparer = new PropertyNameComparer ( ) ;
62
25
63
- MapNestedProperties ( ContextualizationPropertyName , propertiesAddedInContextualization , expression ) ;
64
- }
26
+ private readonly string _sourcePropertyPath = ModelPropertyName ;
27
+ private readonly List < PropertyInfo > _sourceProperties ;
28
+ private readonly List < PropertyInfo > _destinationProperties ;
29
+ private readonly List < PropertyInfo > _referenceProperties ;
30
+ private readonly List < PropertyInfo > _contextualizationProperties ;
65
31
66
32
#region Construction
67
33
@@ -70,85 +36,136 @@ public LinkSourceMapper()
70
36
EnsureHasModelProperty ( ) ;
71
37
EnsureHasModelPropertyWhichIsAClass ( ) ;
72
38
73
- _propertyNameComparer = new PropertyNameComparer ( ) ;
74
- InitModelProperties ( ) ;
75
- InitDestinationProperties ( ) ;
76
- InitReferenceProperties ( ) ;
77
- InitContextualizationProperties ( ) ;
39
+ _sourceProperties = GetModelProperties ( ) ;
40
+ _destinationProperties = GetDestinationProperties ( ) ;
41
+ _referenceProperties = GetReferenceProperties ( ) ;
42
+ _contextualizationProperties = GetContextualizationProperties ( ) ;
78
43
}
79
44
80
- private void InitModelProperties ( )
45
+ public LinkSourceMapper ( Expression < Func < TLinkedSource , object > > sourceProperty )
81
46
{
82
- var linkedSourceType = typeof ( TLinkedSource ) ;
83
- var modelType = linkedSourceType . GetProperty ( ModelPropertyName ) . PropertyType ;
84
- _modelProperties = modelType . GetProperties ( ) . ToList ( ) ;
47
+ if ( ! ( sourceProperty . Body is MemberExpression me ) )
48
+ {
49
+ throw new ArgumentException ( "Expression must be of type System.Linq.Expressions.MemberExpression" , "propertyExpression" ) ;
50
+ }
51
+
52
+ _sourcePropertyPath = GetPropertiesPrefix ( me ) ;
53
+ _sourceProperties = me . Type . GetProperties ( ) . ToList ( ) ;
54
+ _destinationProperties = GetDestinationProperties ( ) ;
55
+ _referenceProperties = GetReferenceProperties ( ) ;
56
+ _contextualizationProperties = GetContextualizationProperties ( ) ;
85
57
}
86
58
87
- private void InitDestinationProperties ( )
59
+ private static List < PropertyInfo > GetModelProperties ( )
88
60
{
89
- var destinationType = typeof ( TDestination ) ;
90
- _destinationProperties = destinationType . GetProperties ( ) . ToList ( ) ;
61
+ var modelType = LinkedSourceType . GetProperty ( ModelPropertyName ) . PropertyType ;
62
+ return modelType . GetProperties ( ) . ToList ( ) ;
91
63
}
92
64
93
- private void InitReferenceProperties ( )
65
+ private static List < PropertyInfo > GetDestinationProperties ( )
94
66
{
95
- var linkedSourceType = typeof ( TLinkedSource ) ;
67
+ return typeof ( TDestination ) . GetProperties ( ) . ToList ( ) ;
68
+ }
96
69
97
- _referenceProperties = linkedSourceType . GetProperties ( )
70
+ private static List < PropertyInfo > GetReferenceProperties ( )
71
+ {
72
+ return LinkedSourceType . GetProperties ( )
98
73
. Where ( property => property . Name != ModelPropertyName )
99
74
. Where ( property => property . Name != ContextualizationPropertyName )
100
75
. ToList ( ) ;
101
76
}
102
77
103
- private void InitContextualizationProperties ( )
78
+ private static List < PropertyInfo > GetContextualizationProperties ( )
104
79
{
105
- var linkedSourceType = typeof ( TLinkedSource ) ;
106
- var modelContextualization = linkedSourceType . GetProperty ( ContextualizationPropertyName ) ;
80
+ var modelContextualization = LinkedSourceType . GetProperty ( ContextualizationPropertyName ) ;
107
81
if ( modelContextualization == null )
108
82
{
109
- _contextualizationProperties = new List < PropertyInfo > ( ) ;
110
- }
111
- else
112
- {
113
- var modelContextualizationType = modelContextualization . PropertyType ;
114
- _contextualizationProperties = modelContextualizationType . GetProperties ( )
115
- // By convention, we don't override the Id using the contextualization
116
- . Where ( property => ! property . Name . Equals ( "Id" , StringComparison . OrdinalIgnoreCase ) )
117
- . ToList ( ) ;
83
+ return new List < PropertyInfo > ( ) ;
118
84
}
85
+
86
+ var modelContextualizationType = modelContextualization . PropertyType ;
87
+ return modelContextualizationType . GetProperties ( )
88
+ // By convention, we don't override the Id using the contextualization
89
+ . Where ( property => ! property . Name . Equals ( "Id" , StringComparison . OrdinalIgnoreCase ) )
90
+ . ToList ( ) ;
119
91
}
120
92
121
93
private static void EnsureHasModelProperty ( )
122
94
{
123
- var linkedSourceType = typeof ( TLinkedSource ) ;
124
- var linkedSourceTypeFullName = linkedSourceType . FullName ;
125
- if ( linkedSourceType . GetProperty ( ModelPropertyName ) == null )
95
+ if ( LinkedSourceType . GetProperty ( ModelPropertyName ) == null )
126
96
throw new ArgumentException (
127
- string . Format (
128
- "{0} must have a property named Model, otherwise it cannot be used as a linked source." ,
129
- linkedSourceTypeFullName
130
- ) ,
131
- "TLinkedSource"
97
+ $ "{ LinkedSourceType . FullName } must have a property named Model, otherwise it cannot be used as a linked source.",
98
+ nameof ( TLinkedSource )
132
99
) ;
133
100
}
134
101
135
102
private static void EnsureHasModelPropertyWhichIsAClass ( )
136
103
{
137
- var linkedSourceType = typeof ( TLinkedSource ) ;
138
- var linkedSourceTypeFullName = linkedSourceType . FullName ;
139
- var modelType = linkedSourceType . GetProperty ( ModelPropertyName ) . PropertyType ;
104
+ var linkedSourceTypeFullName = LinkedSourceType . FullName ;
105
+ var modelType = LinkedSourceType . GetProperty ( ModelPropertyName ) . PropertyType ;
140
106
if ( modelType . IsClass == false )
141
107
throw new ArgumentException (
142
- string . Format (
143
- "{0} must have a property named Model which is a class, otherwise it cannot be used as a linked source." ,
144
- linkedSourceTypeFullName
145
- ) ,
146
- "TLinkedSource"
108
+ $ "{ linkedSourceTypeFullName } must have a property named Model which is a class, otherwise it cannot be used as a linked source.",
109
+ nameof ( TLinkedSource )
147
110
) ;
148
111
}
149
112
150
113
#endregion
151
114
115
+
116
+ public IMappingExpression < TLinkedSource , TDestination > MapLinkedSource ( IMappingExpression < TLinkedSource , TDestination > expression )
117
+ {
118
+ MapModelProperties ( expression ) ;
119
+ MapContextualizedModelProperties ( expression ) ;
120
+ MapPropertiesAddedInContextualization ( expression ) ;
121
+
122
+ return expression ;
123
+ }
124
+
125
+ private static string GetPropertiesPrefix ( MemberExpression me )
126
+ {
127
+ var propertiesPrefix = "" ;
128
+
129
+ while ( me != null )
130
+ {
131
+ propertiesPrefix = string . IsNullOrEmpty ( propertiesPrefix ) ?
132
+ me . Member . Name :
133
+ $ "{ me . Member . Name } .{ propertiesPrefix } ";
134
+ me = me . Expression as MemberExpression ;
135
+ }
136
+
137
+ return propertiesPrefix ;
138
+ }
139
+ private void MapModelProperties ( IMappingExpression < TLinkedSource , TDestination > expression )
140
+ {
141
+ var modelPropertiesToMap = _sourceProperties
142
+ . Intersect ( _destinationProperties , _propertyNameComparer )
143
+ . Except ( _referenceProperties , _propertyNameComparer )
144
+ . Except ( _contextualizationProperties , _propertyNameComparer ) ;
145
+
146
+ MapNestedProperties ( _sourcePropertyPath , modelPropertiesToMap , expression ) ;
147
+ }
148
+
149
+ private void MapContextualizedModelProperties ( IMappingExpression < TLinkedSource , TDestination > expression )
150
+ {
151
+ var contextualizedModelPropertiesToMap = _sourceProperties
152
+ . Intersect ( _destinationProperties , _propertyNameComparer )
153
+ . Intersect ( _contextualizationProperties , _propertyNameComparer )
154
+ . Except ( _referenceProperties , _propertyNameComparer ) ;
155
+
156
+ MapContextualizedProperties ( contextualizedModelPropertiesToMap , expression ) ;
157
+ }
158
+
159
+ private void MapPropertiesAddedInContextualization ( IMappingExpression < TLinkedSource , TDestination > expression )
160
+ {
161
+ var propertiesAddedInContextualization = _contextualizationProperties
162
+ . Intersect ( _destinationProperties , _propertyNameComparer )
163
+ . Except ( _referenceProperties , _propertyNameComparer )
164
+ . Except ( _sourceProperties , _propertyNameComparer ) ;
165
+
166
+ MapNestedProperties ( ContextualizationPropertyName , propertiesAddedInContextualization , expression ) ;
167
+ }
168
+
152
169
#region MapNestedProperties
153
170
154
171
private static void MapNestedProperties (
@@ -158,7 +175,7 @@ private static void MapNestedProperties(
158
175
{
159
176
foreach ( var property in nestedProperties )
160
177
{
161
- var sourcePropertyInDotNotation = string . Format ( "{0 }.{1}" , sourcePropertiesPrefix , property . Name ) ;
178
+ var sourcePropertyInDotNotation = $ " { sourcePropertiesPrefix } .{ property . Name } " ;
162
179
var method = ThisType . GetMethod ( "MapProperty" ) ;
163
180
var genericMethod = method . MakeGenericMethod ( property . PropertyType ) ;
164
181
@@ -183,7 +200,7 @@ public static void MapProperty<TSourceProperty>(
183
200
184
201
private static Expression < Func < TLinkedSource , TProperty > > CreateMemberExpression < TProperty > ( string propertyInDotNotation )
185
202
{
186
- var root = Expression . Parameter ( typeof ( TLinkedSource ) , "root" ) ;
203
+ var root = Expression . Parameter ( LinkedSourceType , "root" ) ;
187
204
var lambdaBody = GenerateGetProperty ( root , propertyInDotNotation ) ;
188
205
return Expression . Lambda < Func < TLinkedSource , TProperty > > ( lambdaBody , root ) ;
189
206
}
@@ -225,7 +242,7 @@ public static void MapContextualizedProperty<TSourceProperty>(
225
242
226
243
private static Func < TLinkedSource , TProperty > CreateContextualizationFunc < TProperty > ( string overridingPropertyInDotNotation , string defaultPropertyInDotNotation )
227
244
{
228
- var root = Expression . Parameter ( typeof ( TLinkedSource ) , "root" ) ;
245
+ var root = Expression . Parameter ( LinkedSourceType , "root" ) ;
229
246
230
247
var contextualizationProperty = GenerateGetProperty ( root , ContextualizationPropertyName ) ;
231
248
0 commit comments