forked from nhibernate/nhibernate-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBasicPropertyAccessor.cs
359 lines (323 loc) · 10.9 KB
/
BasicPropertyAccessor.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
using System;
using System.Collections;
using System.Reflection;
using System.Reflection.Emit;
using NHibernate.Engine;
namespace NHibernate.Properties
{
/// <summary>
/// Accesses mapped property values via a get/set pair, which may be nonpublic.
/// The default (and recommended strategy).
/// </summary>
[Serializable]
public class BasicPropertyAccessor : IPropertyAccessor
{
#region IPropertyAccessor Members
/// <summary>
/// Create a <see cref="BasicGetter"/> for the mapped property.
/// </summary>
/// <param name="type">The <see cref="System.Type"/> to find the Property in.</param>
/// <param name="propertyName">The name of the mapped Property to get.</param>
/// <returns>
/// The <see cref="BasicGetter"/> to use to get the value of the Property from an
/// instance of the <see cref="System.Type"/>.</returns>
/// <exception cref="PropertyNotFoundException" >
/// Thrown when a Property specified by the <c>propertyName</c> could not
/// be found in the <see cref="System.Type"/>.
/// </exception>
public IGetter GetGetter(System.Type type, string propertyName)
{
BasicGetter result = GetGetterOrNull(type, propertyName);
if (result == null)
{
throw new PropertyNotFoundException(type, propertyName, "getter");
}
return result;
}
/// <summary>
/// Create a <see cref="BasicSetter"/> for the mapped property.
/// </summary>
/// <param name="type">The <see cref="System.Type"/> to find the Property in.</param>
/// <param name="propertyName">The name of the mapped Property to get.</param>
/// <returns>
/// The <see cref="BasicSetter"/> to use to set the value of the Property on an
/// instance of the <see cref="System.Type"/>.
/// </returns>
/// <exception cref="PropertyNotFoundException" >
/// Thrown when a Property specified by the <c>propertyName</c> could not
/// be found in the <see cref="System.Type"/>.
/// </exception>
public ISetter GetSetter(System.Type type, string propertyName)
{
BasicSetter result = GetSetterOrNull(type, propertyName);
if (result == null)
{
throw new PropertyNotFoundException(type, propertyName, "setter");
}
return result;
}
public bool CanAccessThroughReflectionOptimizer
{
get { return true; }
}
#endregion
/// <summary>
/// Helper method to find the Property <c>get</c>.
/// </summary>
/// <param name="type">The <see cref="System.Type"/> to find the Property in.</param>
/// <param name="propertyName">The name of the mapped Property to get.</param>
/// <returns>
/// The <see cref="BasicGetter"/> for the Property <c>get</c> or <see langword="null" />
/// if the Property could not be found.
/// </returns>
internal static BasicGetter GetGetterOrNull(System.Type type, string propertyName)
{
if (type == typeof(object) || type == null)
{
// the full inheritance chain has been walked and we could
// not find the Property get
return null;
}
PropertyInfo property =
type.GetProperty(propertyName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
if (property != null && property.CanRead)
{
return new BasicGetter(type, property, propertyName);
}
else
{
// recursively call this method for the base Type
BasicGetter getter = GetGetterOrNull(type.BaseType, propertyName);
// didn't find anything in the base class - check to see if there is
// an explicit interface implementation.
if (getter == null)
{
System.Type[] interfaces = type.GetInterfaces();
for (int i = 0; getter == null && i < interfaces.Length; i++)
{
getter = GetGetterOrNull(interfaces[i], propertyName);
}
}
return getter;
}
}
/// <summary>
/// Helper method to find the Property <c>set</c>.
/// </summary>
/// <param name="type">The <see cref="System.Type"/> to find the Property in.</param>
/// <param name="propertyName">The name of the mapped Property to set.</param>
/// <returns>
/// The <see cref="BasicSetter"/> for the Property <c>set</c> or <see langword="null" />
/// if the Property could not be found.
/// </returns>
internal static BasicSetter GetSetterOrNull(System.Type type, string propertyName)
{
if (type == typeof(object) || type == null)
{
// the full inheritance chain has been walked and we could
// not find the Property get
return null;
}
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
PropertyInfo property = type.GetProperty(propertyName, bindingFlags);
if (property != null && property.CanWrite)
{
return new BasicSetter(type, property, propertyName);
}
// recursively call this method for the base Type
BasicSetter setter = GetSetterOrNull(type.BaseType, propertyName);
// didn't find anything in the base class - check to see if there is
// an explicit interface implementation.
if (setter == null)
{
System.Type[] interfaces = type.GetInterfaces();
for (int i = 0; setter == null && i < interfaces.Length; i++)
{
setter = GetSetterOrNull(interfaces[i], propertyName);
}
}
return setter;
}
/// <summary>
/// An <see cref="IGetter"/> for a Property <c>get</c>.
/// </summary>
[Serializable]
public sealed class BasicGetter : IGetter, IOptimizableGetter
{
private readonly System.Type clazz;
private readonly PropertyInfo property;
private readonly string propertyName;
/// <summary>
/// Initializes a new instance of <see cref="BasicGetter"/>.
/// </summary>
/// <param name="clazz">The <see cref="System.Type"/> that contains the Property <c>get</c>.</param>
/// <param name="property">The <see cref="PropertyInfo"/> for reflection.</param>
/// <param name="propertyName">The name of the Property.</param>
public BasicGetter(System.Type clazz, PropertyInfo property, string propertyName)
{
this.clazz = clazz;
this.property = property;
this.propertyName = propertyName;
}
public PropertyInfo Property
{
get { return property; }
}
#region IGetter Members
/// <summary>
/// Gets the value of the Property from the object.
/// </summary>
/// <param name="target">The object to get the Property value from.</param>
/// <returns>
/// The value of the Property for the target.
/// </returns>
public object Get(object target)
{
try
{
return property.GetValue(target, Array.Empty<object>());
}
catch (Exception e)
{
throw new PropertyAccessException(e, "Exception occurred", false, clazz, propertyName);
}
}
/// <summary>
/// Gets the <see cref="System.Type"/> that the Property returns.
/// </summary>
/// <value>The <see cref="System.Type"/> that the Property returns.</value>
public System.Type ReturnType
{
get { return property.PropertyType; }
}
/// <summary>
/// Gets the name of the Property.
/// </summary>
/// <value>The name of the Property.</value>
public string PropertyName
{
get { return property.Name; }
}
/// <summary>
/// Gets the <see cref="PropertyInfo"/> for the Property.
/// </summary>
/// <value>
/// The <see cref="PropertyInfo"/> for the Property.
/// </value>
public MethodInfo Method
{
get { return property.GetGetMethod(true); }
}
public object GetForInsert(object owner, IDictionary mergeMap, ISessionImplementor session)
{
return Get(owner);
}
#endregion
public void Emit(ILGenerator il)
{
MethodInfo method = Method;
if (method == null)
{
throw new PropertyNotFoundException(clazz, property.Name, "getter");
}
il.EmitCall(OpCodes.Callvirt, method, null);
}
}
/// <summary>
/// An <see cref="ISetter"/> for a Property <c>set</c>.
/// </summary>
[Serializable]
public sealed class BasicSetter : ISetter, IOptimizableSetter
{
private readonly System.Type clazz;
private readonly PropertyInfo property;
private readonly string propertyName;
/// <summary>
/// Initializes a new instance of <see cref="BasicSetter"/>.
/// </summary>
/// <param name="clazz">The <see cref="System.Type"/> that contains the Property <c>set</c>.</param>
/// <param name="property">The <see cref="PropertyInfo"/> for reflection.</param>
/// <param name="propertyName">The name of the mapped Property.</param>
public BasicSetter(System.Type clazz, PropertyInfo property, string propertyName)
{
this.clazz = clazz;
this.property = property;
this.propertyName = propertyName;
}
public PropertyInfo Property
{
get { return property; }
}
#region ISetter Members
/// <summary>
/// Sets the value of the Property on the object.
/// </summary>
/// <param name="target">The object to set the Property value in.</param>
/// <param name="value">The value to set the Property to.</param>
/// <exception cref="PropertyAccessException">
/// Thrown when there is a problem setting the value in the target.
/// </exception>
public void Set(object target, object value)
{
try
{
property.SetValue(target, value, Array.Empty<object>());
}
catch (ArgumentException ae)
{
// if I'm reading the msdn docs correctly this is the only reason the ArgumentException
// would be thrown, but it doesn't hurt to make sure.
if (property.PropertyType.IsInstanceOfType(value) == false)
{
// add some details to the error message - there have been a few forum posts an they are
// all related to an ISet and IDictionary mixups.
string msg =
String.Format("The type {0} can not be assigned to a property of type {1}", value.GetType(),
property.PropertyType);
throw new PropertyAccessException(ae, msg, true, clazz, propertyName);
}
else
{
throw new PropertyAccessException(ae, "ArgumentException while setting the property value by reflection", true,
clazz, propertyName);
}
}
catch (Exception e)
{
throw new PropertyAccessException(e, "could not set a property value by reflection", true, clazz, propertyName);
}
}
/// <summary>
/// Gets the name of the mapped Property.
/// </summary>
/// <value>The name of the mapped Property or <see langword="null" />.</value>
public string PropertyName
{
get { return property.Name; }
}
/// <summary>
/// Gets the <see cref="PropertyInfo"/> for the mapped Property.
/// </summary>
/// <value>The <see cref="PropertyInfo"/> for the mapped Property.</value>
public MethodInfo Method
{
get { return property.GetSetMethod(true); }
}
public System.Type Type
{
get { return property.PropertyType; }
}
#endregion
public void Emit(ILGenerator il)
{
MethodInfo method = Method;
if (method == null)
{
throw new PropertyNotFoundException(clazz, property.Name, "setter");
}
il.EmitCall(OpCodes.Callvirt, method, null);
}
}
}
}