0
|
1 using System;
|
|
2 using System.Collections;
|
|
3 using System.Collections.Generic;
|
|
4 using System.ComponentModel;
|
|
5 using System.Data;
|
|
6 using System.Data.SqlTypes;
|
|
7 using System.Diagnostics;
|
|
8 using System.Diagnostics.CodeAnalysis;
|
|
9 using System.IO;
|
|
10 using System.Reflection;
|
|
11
|
|
12 using BLToolkit.Common;
|
|
13 #if !SILVERLIGHT && !DATA
|
|
14 using BLToolkit.ComponentModel;
|
|
15 using BLToolkit.EditableObjects;
|
|
16 #endif
|
|
17 using BLToolkit.Mapping;
|
|
18 using BLToolkit.TypeBuilder;
|
|
19 using BLToolkit.TypeBuilder.Builders;
|
|
20
|
|
21 using JNotNull = JetBrains.Annotations.NotNullAttribute;
|
|
22
|
|
23 namespace BLToolkit.Reflection
|
|
24 {
|
|
25 public delegate object NullValueProvider(Type type);
|
|
26 public delegate bool IsNullHandler (object obj);
|
|
27
|
|
28 [DebuggerDisplay("Type = {Type}, OriginalType = {OriginalType}")]
|
|
29 public abstract class TypeAccessor : ICollection<MemberAccessor>
|
|
30 #if !SILVERLIGHT && !DATA
|
|
31 , ITypeDescriptionProvider
|
|
32 #endif
|
|
33 {
|
|
34 #region Protected Emit Helpers
|
|
35
|
|
36 protected MemberInfo GetMember(int memberType, string memberName)
|
|
37 {
|
|
38 const BindingFlags allInstaceMembers =
|
|
39 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
|
40 MemberInfo mi;
|
|
41
|
|
42 switch (memberType)
|
|
43 {
|
|
44 case 1: mi = Type.GetField (memberName, allInstaceMembers); break;
|
|
45 case 2:
|
|
46 mi =
|
|
47 Type. GetProperty(memberName, allInstaceMembers) ??
|
|
48 OriginalType.GetProperty(memberName, allInstaceMembers);
|
|
49 break;
|
|
50 default:
|
|
51 throw new InvalidOperationException();
|
|
52 }
|
|
53
|
|
54 return mi;
|
|
55 }
|
|
56
|
|
57 protected void AddMember(MemberAccessor member)
|
|
58 {
|
|
59 if (member == null) throw new ArgumentNullException("member");
|
|
60
|
|
61 _members.Add(member);
|
|
62 _memberNames.Add(member.MemberInfo.Name, member);
|
|
63 }
|
|
64
|
|
65 #endregion
|
|
66
|
|
67 #region CreateInstance
|
|
68
|
|
69 [DebuggerStepThrough]
|
|
70 public virtual object CreateInstance()
|
|
71 {
|
|
72 throw new TypeBuilderException(string.Format(
|
|
73 "The '{0}' type must have public default or init constructor.",
|
|
74 OriginalType.Name));
|
|
75 }
|
|
76
|
|
77 [DebuggerStepThrough]
|
|
78 public virtual object CreateInstance(InitContext context)
|
|
79 {
|
|
80 return CreateInstance();
|
|
81 }
|
|
82
|
|
83 [DebuggerStepThrough]
|
|
84 public object CreateInstanceEx()
|
|
85 {
|
|
86 return _objectFactory != null?
|
|
87 _objectFactory.CreateInstance(this, null): CreateInstance((InitContext)null);
|
|
88 }
|
|
89
|
|
90 [DebuggerStepThrough]
|
|
91 public object CreateInstanceEx(InitContext context)
|
|
92 {
|
|
93 return _objectFactory != null? _objectFactory.CreateInstance(this, context): CreateInstance(context);
|
|
94 }
|
|
95
|
|
96 #endregion
|
|
97
|
|
98 #region ObjectFactory
|
|
99
|
|
100 private IObjectFactory _objectFactory;
|
|
101 public IObjectFactory ObjectFactory
|
|
102 {
|
|
103 get { return _objectFactory; }
|
|
104 set { _objectFactory = value; }
|
|
105 }
|
|
106
|
|
107 #endregion
|
|
108
|
|
109 #region Copy & AreEqual
|
|
110
|
|
111 internal static object CopyInternal(object source, object dest, TypeAccessor ta)
|
|
112 {
|
|
113 #if !SILVERLIGHT && !DATA
|
|
114 var isDirty = false;
|
|
115 var sourceEditable = source as IMemberwiseEditable;
|
|
116 var destEditable = dest as IMemberwiseEditable;
|
|
117
|
|
118 if (sourceEditable != null && destEditable != null)
|
|
119 {
|
|
120 foreach (MemberAccessor ma in ta)
|
|
121 {
|
|
122 ma.CloneValue(source, dest);
|
|
123 if (sourceEditable.IsDirtyMember(null, ma.MemberInfo.Name, ref isDirty) && !isDirty)
|
|
124 destEditable.AcceptMemberChanges(null, ma.MemberInfo.Name);
|
|
125 }
|
|
126 }
|
|
127 else
|
|
128 #endif
|
|
129 {
|
|
130 foreach (MemberAccessor ma in ta)
|
|
131 ma.CloneValue(source, dest);
|
|
132 }
|
|
133
|
|
134 return dest;
|
|
135 }
|
|
136
|
|
137 public static object Copy(object source, object dest)
|
|
138 {
|
|
139 if (source == null) throw new ArgumentNullException("source");
|
|
140 if (dest == null) throw new ArgumentNullException("dest");
|
|
141
|
|
142 TypeAccessor ta;
|
|
143
|
|
144 var sType = source.GetType();
|
|
145 var dType = dest. GetType();
|
|
146
|
|
147 if (TypeHelper.IsSameOrParent(sType, dType)) ta = GetAccessor(sType);
|
|
148 else if (TypeHelper.IsSameOrParent(dType, sType)) ta = GetAccessor(dType);
|
|
149 else
|
|
150 throw new ArgumentException();
|
|
151
|
|
152 return CopyInternal(source, dest, ta);
|
|
153 }
|
|
154
|
|
155 public static object Copy(object source)
|
|
156 {
|
|
157 if (source == null) throw new ArgumentNullException("source");
|
|
158
|
|
159 var ta = GetAccessor(source.GetType());
|
|
160
|
|
161 return CopyInternal(source, ta.CreateInstanceEx(), ta);
|
|
162 }
|
|
163
|
|
164 public static bool AreEqual(object obj1, object obj2)
|
|
165 {
|
|
166 if (ReferenceEquals(obj1, obj2))
|
|
167 return true;
|
|
168
|
|
169 if (obj1 == null || obj2 == null)
|
|
170 return false;
|
|
171
|
|
172 TypeAccessor ta;
|
|
173
|
|
174 var sType = obj1.GetType();
|
|
175 var dType = obj2.GetType();
|
|
176
|
|
177 if (TypeHelper.IsSameOrParent(sType, dType)) ta = GetAccessor(sType);
|
|
178 else if (TypeHelper.IsSameOrParent(dType, sType)) ta = GetAccessor(dType);
|
|
179 else
|
|
180 return false;
|
|
181
|
|
182 foreach (MemberAccessor ma in ta)
|
|
183 if ((!Equals(ma.GetValue(obj1), ma.GetValue(obj2))))
|
|
184 return false;
|
|
185
|
|
186 return true;
|
|
187 }
|
|
188
|
|
189 public static int GetHashCode(object obj)
|
|
190 {
|
|
191 if (obj == null)
|
|
192 throw new ArgumentNullException("obj");
|
|
193
|
|
194 var hash = 0;
|
|
195 object value;
|
|
196
|
|
197 foreach (MemberAccessor ma in GetAccessor(obj.GetType()))
|
|
198 {
|
|
199 value = ma.GetValue(obj);
|
|
200 hash = ((hash << 5) + hash) ^ (value == null ? 0 : value.GetHashCode());
|
|
201 }
|
|
202
|
|
203 return hash;
|
|
204 }
|
|
205
|
|
206 #endregion
|
|
207
|
|
208 #region Abstract Members
|
|
209
|
|
210 public abstract Type Type { get; }
|
|
211 public abstract Type OriginalType { get; }
|
|
212
|
|
213 #endregion
|
|
214
|
|
215 #region Items
|
|
216
|
|
217 private readonly List<MemberAccessor> _members = new List<MemberAccessor>();
|
|
218 private readonly Dictionary<string,MemberAccessor> _memberNames = new Dictionary<string,MemberAccessor>();
|
|
219
|
|
220 public MemberAccessor this[string memberName]
|
|
221 {
|
|
222 get
|
|
223 {
|
|
224 MemberAccessor ma;
|
|
225 return _memberNames.TryGetValue(memberName, out ma) ? ma : null;
|
|
226 }
|
|
227 }
|
|
228
|
|
229 public MemberAccessor this[int index]
|
|
230 {
|
|
231 get { return _members[index]; }
|
|
232 }
|
|
233
|
|
234 public MemberAccessor this[NameOrIndexParameter nameOrIndex]
|
|
235 {
|
|
236 get
|
|
237 {
|
|
238 return nameOrIndex.ByName ? _memberNames[nameOrIndex.Name] : _members[nameOrIndex.Index];
|
|
239 }
|
|
240 }
|
|
241
|
|
242 #endregion
|
|
243
|
|
244 #region Static Members
|
|
245
|
|
246 [Obsolete("Use TypeFactory.LoadTypes instead")]
|
|
247 public static bool LoadTypes
|
|
248 {
|
|
249 get { return TypeFactory.LoadTypes; }
|
|
250 set { TypeFactory.LoadTypes = value; }
|
|
251 }
|
|
252
|
|
253 private static readonly Dictionary<Type,TypeAccessor> _accessors = new Dictionary<Type,TypeAccessor>(10);
|
|
254
|
|
255 public static TypeAccessor GetAccessor(Type originalType)
|
|
256 {
|
|
257 if (originalType == null) throw new ArgumentNullException("originalType");
|
|
258
|
|
259 lock (_accessors)
|
|
260 {
|
|
261 TypeAccessor accessor;
|
|
262
|
|
263 if (_accessors.TryGetValue(originalType, out accessor))
|
|
264 return accessor;
|
|
265
|
|
266 if (IsAssociatedType(originalType))
|
|
267 return _accessors[originalType];
|
|
268
|
|
269 var instanceType = (IsClassBulderNeeded(originalType) ? null : originalType) ?? TypeFactory.GetType(originalType);
|
|
270
|
|
271 var accessorType = TypeFactory.GetType(originalType, originalType, new TypeAccessorBuilder(instanceType, originalType));
|
|
272
|
|
273 accessor = (TypeAccessor)Activator.CreateInstance(accessorType);
|
|
274
|
|
275 _accessors.Add(originalType, accessor);
|
|
276
|
|
277 if (originalType != instanceType)
|
|
278 _accessors.Add(instanceType, accessor);
|
|
279
|
|
280 return accessor;
|
|
281 }
|
|
282 }
|
|
283
|
|
284 public static TypeAccessor GetAccessor([JNotNull] object obj)
|
|
285 {
|
|
286 if (obj == null) throw new ArgumentNullException("obj");
|
|
287 return GetAccessor(obj.GetType());
|
|
288 }
|
|
289
|
|
290 public static TypeAccessor GetAccessor<T>()
|
|
291 {
|
|
292 return TypeAccessor<T>.Instance;
|
|
293 }
|
|
294
|
|
295 private static bool IsClassBulderNeeded(Type type)
|
|
296 {
|
|
297 if (type.IsAbstract && !type.IsSealed)
|
|
298 {
|
|
299 if (!type.IsInterface)
|
|
300 {
|
|
301 if (TypeHelper.GetDefaultConstructor(type) != null)
|
|
302 return true;
|
|
303
|
|
304 if (TypeHelper.GetConstructor(type, typeof(InitContext)) != null)
|
|
305 return true;
|
|
306 }
|
|
307 else
|
|
308 {
|
|
309 var attrs = TypeHelper.GetAttributes(type, typeof(AutoImplementInterfaceAttribute));
|
|
310
|
|
311 if (attrs != null && attrs.Length > 0)
|
|
312 return true;
|
|
313 }
|
|
314 }
|
|
315
|
|
316 return false;
|
|
317 }
|
|
318
|
|
319 internal static bool IsInstanceBuildable(Type type)
|
|
320 {
|
|
321 if (!type.IsInterface)
|
|
322 return true;
|
|
323
|
|
324 lock (_accessors)
|
|
325 {
|
|
326 if (_accessors.ContainsKey(type))
|
|
327 return true;
|
|
328
|
|
329 if (IsAssociatedType(type))
|
|
330 return true;
|
|
331 }
|
|
332
|
|
333 var attrs = TypeHelper.GetAttributes(type, typeof(AutoImplementInterfaceAttribute));
|
|
334
|
|
335 return attrs != null && attrs.Length > 0;
|
|
336 }
|
|
337
|
|
338 private static bool IsAssociatedType(Type type)
|
|
339 {
|
|
340 if (AssociatedTypeHandler != null)
|
|
341 {
|
|
342 var child = AssociatedTypeHandler(type);
|
|
343
|
|
344 if (child != null)
|
|
345 {
|
|
346 AssociateType(type, child);
|
|
347 return true;
|
|
348 }
|
|
349 }
|
|
350
|
|
351 return false;
|
|
352 }
|
|
353
|
|
354 public static object CreateInstance(Type type)
|
|
355 {
|
|
356 return GetAccessor(type).CreateInstance();
|
|
357 }
|
|
358
|
|
359 public static object CreateInstance(Type type, InitContext context)
|
|
360 {
|
|
361 return GetAccessor(type).CreateInstance(context);
|
|
362 }
|
|
363
|
|
364 public static object CreateInstanceEx(Type type)
|
|
365 {
|
|
366 return GetAccessor(type).CreateInstanceEx();
|
|
367 }
|
|
368
|
|
369 public static object CreateInstanceEx(Type type, InitContext context)
|
|
370 {
|
|
371 return GetAccessor(type).CreateInstance(context);
|
|
372 }
|
|
373
|
|
374 public static T CreateInstance<T>()
|
|
375 {
|
|
376 return TypeAccessor<T>.CreateInstance();
|
|
377 }
|
|
378
|
|
379 public static T CreateInstance<T>(InitContext context)
|
|
380 {
|
|
381 return TypeAccessor<T>.CreateInstance(context);
|
|
382 }
|
|
383
|
|
384 public static T CreateInstanceEx<T>()
|
|
385 {
|
|
386 return TypeAccessor<T>.CreateInstanceEx();
|
|
387 }
|
|
388
|
|
389 public static T CreateInstanceEx<T>(InitContext context)
|
|
390 {
|
|
391 return TypeAccessor<T>.CreateInstance(context);
|
|
392 }
|
|
393
|
|
394 public static TypeAccessor AssociateType(Type parent, Type child)
|
|
395 {
|
|
396 if (!TypeHelper.IsSameOrParent(parent, child))
|
|
397 throw new ArgumentException(
|
|
398 string.Format("'{0}' must be a base type of '{1}'", parent, child),
|
|
399 "child");
|
|
400
|
|
401 var accessor = GetAccessor(child);
|
|
402
|
|
403 accessor = (TypeAccessor)Activator.CreateInstance(accessor.GetType());
|
|
404
|
|
405 lock (_accessors)
|
|
406 _accessors.Add(parent, accessor);
|
|
407
|
|
408 return accessor;
|
|
409 }
|
|
410
|
|
411 public delegate Type GetAssociatedType(Type parent);
|
|
412 public static event GetAssociatedType AssociatedTypeHandler;
|
|
413
|
|
414 #endregion
|
|
415
|
|
416 #region GetNullValue
|
|
417
|
|
418 private static NullValueProvider _getNullValue = GetNullInternal;
|
|
419 public static NullValueProvider GetNullValue
|
|
420 {
|
|
421 get { return _getNullValue ?? (_getNullValue = GetNullInternal);}
|
|
422 set { _getNullValue = value; }
|
|
423 }
|
|
424
|
|
425 private static object GetNullInternal(Type type)
|
|
426 {
|
|
427 if (type == null) throw new ArgumentNullException("type");
|
|
428
|
|
429 if (type.IsValueType)
|
|
430 {
|
|
431 if (type.IsEnum)
|
|
432 return GetEnumNullValue(type);
|
|
433
|
|
434 if (type.IsPrimitive)
|
|
435 {
|
|
436 if (type == typeof(Int32)) return Common.Configuration.NullableValues.Int32;
|
|
437 if (type == typeof(Double)) return Common.Configuration.NullableValues.Double;
|
|
438 if (type == typeof(Int16)) return Common.Configuration.NullableValues.Int16;
|
|
439 if (type == typeof(Boolean)) return Common.Configuration.NullableValues.Boolean;
|
|
440 if (type == typeof(SByte)) return Common.Configuration.NullableValues.SByte;
|
|
441 if (type == typeof(Int64)) return Common.Configuration.NullableValues.Int64;
|
|
442 if (type == typeof(Byte)) return Common.Configuration.NullableValues.Byte;
|
|
443 if (type == typeof(UInt16)) return Common.Configuration.NullableValues.UInt16;
|
|
444 if (type == typeof(UInt32)) return Common.Configuration.NullableValues.UInt32;
|
|
445 if (type == typeof(UInt64)) return Common.Configuration.NullableValues.UInt64;
|
|
446 if (type == typeof(Single)) return Common.Configuration.NullableValues.Single;
|
|
447 if (type == typeof(Char)) return Common.Configuration.NullableValues.Char;
|
|
448 }
|
|
449 else
|
|
450 {
|
|
451 if (type == typeof(DateTime)) return Common.Configuration.NullableValues.DateTime;
|
|
452 if (type == typeof(DateTimeOffset)) return Common.Configuration.NullableValues.DateTimeOffset;
|
|
453 if (type == typeof(Decimal)) return Common.Configuration.NullableValues.Decimal;
|
|
454 if (type == typeof(Guid)) return Common.Configuration.NullableValues.Guid;
|
|
455
|
|
456 #if !SILVERLIGHT
|
|
457
|
|
458 if (type == typeof(SqlInt32)) return SqlInt32. Null;
|
|
459 if (type == typeof(SqlString)) return SqlString. Null;
|
|
460 if (type == typeof(SqlBoolean)) return SqlBoolean. Null;
|
|
461 if (type == typeof(SqlByte)) return SqlByte. Null;
|
|
462 if (type == typeof(SqlDateTime)) return SqlDateTime.Null;
|
|
463 if (type == typeof(SqlDecimal)) return SqlDecimal. Null;
|
|
464 if (type == typeof(SqlDouble)) return SqlDouble. Null;
|
|
465 if (type == typeof(SqlGuid)) return SqlGuid. Null;
|
|
466 if (type == typeof(SqlInt16)) return SqlInt16. Null;
|
|
467 if (type == typeof(SqlInt64)) return SqlInt64. Null;
|
|
468 if (type == typeof(SqlMoney)) return SqlMoney. Null;
|
|
469 if (type == typeof(SqlSingle)) return SqlSingle. Null;
|
|
470 if (type == typeof(SqlBinary)) return SqlBinary. Null;
|
|
471
|
|
472 #endif
|
|
473 }
|
|
474 }
|
|
475 else
|
|
476 {
|
|
477 if (type == typeof(String)) return Common.Configuration.NullableValues.String;
|
|
478 if (type == typeof(DBNull)) return DBNull.Value;
|
|
479 if (type == typeof(Stream)) return Stream.Null;
|
|
480 #if !SILVERLIGHT
|
|
481 if (type == typeof(SqlXml)) return SqlXml.Null;
|
|
482 #endif
|
|
483 }
|
|
484
|
|
485 return null;
|
|
486 }
|
|
487
|
|
488 const FieldAttributes EnumField = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
|
|
489
|
|
490 static readonly Dictionary<Type,object> _nullValues = new Dictionary<Type,object>();
|
|
491
|
|
492 static object GetEnumNullValue(Type type)
|
|
493 {
|
|
494 object nullValue;
|
|
495
|
|
496 lock (_nullValues)
|
|
497 if (_nullValues.TryGetValue(type, out nullValue))
|
|
498 return nullValue;
|
|
499
|
|
500 var fields = type.GetFields();
|
|
501
|
|
502 foreach (var fi in fields)
|
|
503 {
|
|
504 if ((fi.Attributes & EnumField) == EnumField)
|
|
505 {
|
|
506 var attrs = Attribute.GetCustomAttributes(fi, typeof(NullValueAttribute));
|
|
507
|
|
508 if (attrs.Length > 0)
|
|
509 {
|
|
510 nullValue = Enum.Parse(type, fi.Name, false);
|
|
511 break;
|
|
512 }
|
|
513 }
|
|
514 }
|
|
515
|
|
516 lock (_nullValues)
|
|
517 if (!_nullValues.ContainsKey(type))
|
|
518 _nullValues.Add(type, nullValue);
|
|
519
|
|
520 return nullValue;
|
|
521 }
|
|
522
|
|
523 private static IsNullHandler _isNull = IsNullInternal;
|
|
524 public static IsNullHandler IsNull
|
|
525 {
|
|
526 get { return _isNull ?? (_isNull = IsNullInternal); }
|
|
527 set { _isNull = value; }
|
|
528 }
|
|
529
|
|
530 private static bool IsNullInternal(object value)
|
|
531 {
|
|
532 if (value == null)
|
|
533 return true;
|
|
534
|
|
535 var nullValue = GetNullValue(value.GetType());
|
|
536
|
|
537 return nullValue != null && value.Equals(nullValue);
|
|
538 }
|
|
539
|
|
540 #endregion
|
|
541
|
|
542 #region ICollection Members
|
|
543
|
|
544 void ICollection<MemberAccessor>.Add(MemberAccessor item)
|
|
545 {
|
|
546 _members.Add(item);
|
|
547 }
|
|
548
|
|
549 void ICollection<MemberAccessor>.Clear()
|
|
550 {
|
|
551 _members.Clear();
|
|
552 }
|
|
553
|
|
554 bool ICollection<MemberAccessor>.Contains(MemberAccessor item)
|
|
555 {
|
|
556 return _members.Contains(item);
|
|
557 }
|
|
558
|
|
559 void ICollection<MemberAccessor>.CopyTo(MemberAccessor[] array, int arrayIndex)
|
|
560 {
|
|
561 _members.CopyTo(array, arrayIndex);
|
|
562 }
|
|
563
|
|
564 bool ICollection<MemberAccessor>.Remove(MemberAccessor item)
|
|
565 {
|
|
566 return _members.Remove(item);
|
|
567 }
|
|
568
|
|
569 public int Count
|
|
570 {
|
|
571 get { return _members.Count; }
|
|
572 }
|
|
573
|
|
574 bool ICollection<MemberAccessor>.IsReadOnly
|
|
575 {
|
|
576 get { return ((ICollection<MemberAccessor>)_members).IsReadOnly; }
|
|
577 }
|
|
578
|
|
579 public int IndexOf(MemberAccessor ma)
|
|
580 {
|
|
581 return _members.IndexOf(ma);
|
|
582 }
|
|
583
|
|
584 #endregion
|
|
585
|
|
586 #region IEnumerable Members
|
|
587
|
|
588 public IEnumerator GetEnumerator()
|
|
589 {
|
|
590 return _members.GetEnumerator();
|
|
591 }
|
|
592
|
|
593 #endregion
|
|
594
|
|
595 #region IEnumerable<MemberAccessor> Members
|
|
596
|
|
597 IEnumerator<MemberAccessor> IEnumerable<MemberAccessor>.GetEnumerator()
|
|
598 {
|
|
599 foreach (MemberAccessor member in _members)
|
|
600 yield return member;
|
|
601 }
|
|
602
|
|
603 #endregion
|
|
604
|
|
605 #region Write Object Info
|
|
606
|
|
607 public static void WriteDebug(object o)
|
|
608 {
|
|
609 #if DEBUG
|
|
610 Write(o, DebugWriteLine);
|
|
611 #endif
|
|
612 }
|
|
613
|
|
614 private static void DebugWriteLine(string text)
|
|
615 {
|
|
616 Debug.WriteLine(text);
|
|
617 }
|
|
618
|
|
619 public static void WriteConsole(object o)
|
|
620 {
|
|
621 Write(o, Console.WriteLine);
|
|
622 }
|
|
623
|
|
624 [SuppressMessage("Microsoft.Performance", "CA1818:DoNotConcatenateStringsInsideLoops")]
|
|
625 private static string MapTypeName(Type type)
|
|
626 {
|
|
627 if (type.IsGenericType)
|
|
628 {
|
|
629 if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
|
630 return string.Format("{0}?", MapTypeName(Nullable.GetUnderlyingType(type)));
|
|
631
|
|
632 var name = type.Name;
|
|
633 var idx = name.IndexOf('`');
|
|
634
|
|
635 if (idx >= 0)
|
|
636 name = name.Substring(0, idx);
|
|
637
|
|
638 name += "<";
|
|
639
|
|
640 foreach (var t in type.GetGenericArguments())
|
|
641 name += MapTypeName(t) + ',';
|
|
642
|
|
643 if (name[name.Length - 1] == ',')
|
|
644 name = name.Substring(0, name.Length - 1);
|
|
645
|
|
646 name += ">";
|
|
647
|
|
648 return name;
|
|
649 }
|
|
650
|
|
651 if (type.IsPrimitive ||
|
|
652 type == typeof(string) ||
|
|
653 type == typeof(object) ||
|
|
654 type == typeof(decimal))
|
|
655 {
|
|
656 if (type == typeof(int)) return "int";
|
|
657 if (type == typeof(bool)) return "bool";
|
|
658 if (type == typeof(short)) return "short";
|
|
659 if (type == typeof(long)) return "long";
|
|
660 if (type == typeof(ushort)) return "ushort";
|
|
661 if (type == typeof(uint)) return "uint";
|
|
662 if (type == typeof(ulong)) return "ulong";
|
|
663 if (type == typeof(float)) return "float";
|
|
664
|
|
665 return type.Name.ToLower();
|
|
666 }
|
|
667
|
|
668 return type.Name;
|
|
669 }
|
|
670
|
|
671 public delegate void WriteLine(string text);
|
|
672
|
|
673 [SuppressMessage("Microsoft.Usage", "CA2241:ProvideCorrectArgumentsToFormattingMethods")]
|
|
674 public static void Write(object o, WriteLine writeLine)
|
|
675 {
|
|
676 if (o == null)
|
|
677 {
|
|
678 writeLine("*** (null) ***");
|
|
679 return;
|
|
680 }
|
|
681
|
|
682 MemberAccessor ma;
|
|
683
|
|
684 var ta = GetAccessor(o.GetType());
|
|
685 var nameLen = 0;
|
|
686 var typeLen = 0;
|
|
687
|
|
688 foreach (var de in ta._memberNames)
|
|
689 {
|
|
690 if (nameLen < de.Key.Length)
|
|
691 nameLen = de.Key.Length;
|
|
692
|
|
693 ma = de.Value;
|
|
694
|
|
695 if (typeLen < MapTypeName(ma.Type).Length)
|
|
696 typeLen = MapTypeName(ma.Type).Length;
|
|
697 }
|
|
698
|
|
699 var text = "*** " + o.GetType().FullName + ": ***";
|
|
700
|
|
701 writeLine(text);
|
|
702
|
|
703 var format = string.Format("{{0,-{0}}} {{1,-{1}}} : {{2}}", typeLen, nameLen);
|
|
704
|
|
705 foreach (var de in ta._memberNames)
|
|
706 {
|
|
707 ma = de.Value;
|
|
708
|
|
709 var value = ma.GetValue(o);
|
|
710
|
|
711 if (value == null)
|
|
712 value = "(null)";
|
|
713 else if (value is ICollection)
|
|
714 value = string.Format("(Count = {0})", ((ICollection)value).Count);
|
|
715
|
|
716 text = string.Format(format, MapTypeName(ma.Type), de.Key, value);
|
|
717
|
|
718 writeLine(text);
|
|
719 }
|
|
720
|
|
721 writeLine("***");
|
|
722 }
|
|
723
|
|
724 #endregion
|
|
725
|
|
726 #region TypeDescriptor
|
|
727
|
|
728 #if !SILVERLIGHT && !DATA
|
|
729
|
|
730 #region CustomTypeDescriptor
|
|
731
|
|
732 private static readonly Hashtable _descriptors = new Hashtable();
|
|
733
|
|
734 public static ICustomTypeDescriptor GetCustomTypeDescriptor(Type type)
|
|
735 {
|
|
736 var descriptor = (ICustomTypeDescriptor)_descriptors[type];
|
|
737
|
|
738 if (descriptor == null)
|
|
739 {
|
|
740 lock (_descriptors.SyncRoot)
|
|
741 {
|
|
742 descriptor = (ICustomTypeDescriptor)_descriptors[type];
|
|
743
|
|
744 if (descriptor == null)
|
|
745 {
|
|
746 descriptor = new CustomTypeDescriptorImpl(type);
|
|
747
|
|
748 _descriptors.Add(type, descriptor);
|
|
749 }
|
|
750 }
|
|
751 }
|
|
752 return descriptor;
|
|
753 }
|
|
754
|
|
755 private ICustomTypeDescriptor _customTypeDescriptor;
|
|
756 public ICustomTypeDescriptor CustomTypeDescriptor
|
|
757 {
|
|
758 get { return _customTypeDescriptor ?? (_customTypeDescriptor = GetCustomTypeDescriptor(OriginalType)); }
|
|
759 }
|
|
760
|
|
761 #endregion
|
|
762
|
|
763 #region Property Descriptors
|
|
764
|
|
765 private PropertyDescriptorCollection _propertyDescriptors;
|
|
766 public PropertyDescriptorCollection PropertyDescriptors
|
|
767 {
|
|
768 get
|
|
769 {
|
|
770 if (_propertyDescriptors == null)
|
|
771 {
|
|
772 if (TypeHelper.IsSameOrParent(typeof(ICustomTypeDescriptor), OriginalType))
|
|
773 {
|
|
774 var descriptor = CreateInstance() as ICustomTypeDescriptor;
|
|
775
|
|
776 if (descriptor != null)
|
|
777 _propertyDescriptors = descriptor.GetProperties();
|
|
778 }
|
|
779
|
|
780 if (_propertyDescriptors == null)
|
|
781 _propertyDescriptors = CreatePropertyDescriptors();
|
|
782 }
|
|
783
|
|
784 return _propertyDescriptors;
|
|
785 }
|
|
786 }
|
|
787
|
|
788 public PropertyDescriptorCollection CreatePropertyDescriptors()
|
|
789 {
|
|
790 if (Data.DbManager.TraceSwitch.TraceInfo)
|
|
791 Data.DbManager.WriteTraceLine(OriginalType.FullName, "CreatePropertyDescriptors");
|
|
792
|
|
793 var pd = new PropertyDescriptor[Count];
|
|
794
|
|
795 var i = 0;
|
|
796 foreach (MemberAccessor ma in _members)
|
|
797 pd[i++] = ma.PropertyDescriptor;
|
|
798
|
|
799 return new PropertyDescriptorCollection(pd);
|
|
800 }
|
|
801
|
|
802 public PropertyDescriptorCollection CreateExtendedPropertyDescriptors(
|
|
803 Type objectViewType,
|
|
804 IsNullHandler isNull)
|
|
805 {
|
|
806 // This is definitely wrong.
|
|
807 //
|
|
808 //if (isNull == null)
|
|
809 // isNull = _isNull;
|
|
810
|
|
811 var pdc = CreatePropertyDescriptors();
|
|
812
|
|
813 if (objectViewType != null)
|
|
814 {
|
|
815 var viewAccessor = GetAccessor(objectViewType);
|
|
816 var objectView = (IObjectView)viewAccessor.CreateInstanceEx();
|
|
817 var list = new List<PropertyDescriptor>();
|
|
818
|
|
819 var viewpdc = viewAccessor.PropertyDescriptors;
|
|
820
|
|
821 foreach (PropertyDescriptor pd in viewpdc)
|
|
822 list.Add(new ObjectViewPropertyDescriptor(pd, objectView));
|
|
823
|
|
824 foreach (PropertyDescriptor pd in pdc)
|
|
825 if (viewpdc.Find(pd.Name, false) == null)
|
|
826 list.Add(pd);
|
|
827
|
|
828 pdc = new PropertyDescriptorCollection(list.ToArray());
|
|
829 }
|
|
830
|
|
831 pdc = pdc.Sort(new PropertyDescriptorComparer());
|
|
832
|
|
833 pdc = GetExtendedProperties(pdc, OriginalType, String.Empty, Type.EmptyTypes, new PropertyDescriptor[0], isNull);
|
|
834
|
|
835 return pdc;
|
|
836 }
|
|
837
|
|
838 private static PropertyDescriptorCollection GetExtendedProperties(
|
|
839 PropertyDescriptorCollection pdc,
|
|
840 Type itemType,
|
|
841 string propertyPrefix,
|
|
842 Type[] parentTypes,
|
|
843 PropertyDescriptor[] parentAccessors,
|
|
844 IsNullHandler isNull)
|
|
845 {
|
|
846 var list = new ArrayList(pdc.Count);
|
|
847 var objects = new ArrayList();
|
|
848 var isDataRow = itemType.IsSubclassOf(typeof(DataRow));
|
|
849
|
|
850 foreach (PropertyDescriptor p in pdc)
|
|
851 {
|
|
852 var propertyType = p.PropertyType;
|
|
853
|
|
854 if (p.Attributes.Matches(BindableAttribute.No) ||
|
|
855 //propertyType == typeof(Type) ||
|
|
856 isDataRow && p.Name == "ItemArray")
|
|
857 continue;
|
|
858
|
|
859 var isList = false;
|
|
860 var explicitlyBound = p.Attributes.Contains(BindableAttribute.Yes);
|
|
861 var pd = p;
|
|
862
|
|
863 if (propertyType.GetInterface("IList") != null)
|
|
864 {
|
|
865 //if (!explicitlyBound)
|
|
866 // continue;
|
|
867
|
|
868 isList = true;
|
|
869 pd = new ListPropertyDescriptor(pd);
|
|
870 }
|
|
871
|
|
872 if (!isList &&
|
|
873 !propertyType.IsValueType &&
|
|
874 !propertyType.IsArray &&
|
|
875 (!propertyType.FullName.StartsWith("System.") || explicitlyBound
|
|
876 || propertyType.IsGenericType) &&
|
|
877 propertyType != typeof(Type) &&
|
|
878 propertyType != typeof(string) &&
|
|
879 propertyType != typeof(object) &&
|
|
880 Array.IndexOf(parentTypes, propertyType) == -1)
|
|
881 {
|
|
882 var childParentTypes = new Type[parentTypes.Length + 1];
|
|
883
|
|
884 parentTypes.CopyTo(childParentTypes, 0);
|
|
885 childParentTypes[parentTypes.Length] = itemType;
|
|
886
|
|
887 var childParentAccessors = new PropertyDescriptor[parentAccessors.Length + 1];
|
|
888
|
|
889 parentAccessors.CopyTo(childParentAccessors, 0);
|
|
890 childParentAccessors[parentAccessors.Length] = pd;
|
|
891
|
|
892 var pdch = GetAccessor(propertyType).PropertyDescriptors;
|
|
893
|
|
894 pdch = pdch.Sort(new PropertyDescriptorComparer());
|
|
895 pdch = GetExtendedProperties(
|
|
896 pdch,
|
|
897 propertyType,
|
|
898 propertyPrefix + pd.Name + "+",
|
|
899 childParentTypes,
|
|
900 childParentAccessors,
|
|
901 isNull);
|
|
902
|
|
903 objects.AddRange(pdch);
|
|
904 }
|
|
905 else
|
|
906 {
|
|
907 if (propertyPrefix.Length != 0 || isNull != null)
|
|
908 pd = new StandardPropertyDescriptor(pd, propertyPrefix, parentAccessors, isNull);
|
|
909
|
|
910 list.Add(pd);
|
|
911 }
|
|
912 }
|
|
913
|
|
914 list.AddRange(objects);
|
|
915
|
|
916 return new PropertyDescriptorCollection(
|
|
917 (PropertyDescriptor[])list.ToArray(typeof(PropertyDescriptor)));
|
|
918 }
|
|
919
|
|
920 #region PropertyDescriptorComparer
|
|
921
|
|
922 class PropertyDescriptorComparer : IComparer
|
|
923 {
|
|
924 public int Compare(object x, object y)
|
|
925 {
|
|
926 return String.Compare(((PropertyDescriptor)x).Name, ((PropertyDescriptor)y).Name);
|
|
927 }
|
|
928 }
|
|
929
|
|
930 #endregion
|
|
931
|
|
932 #region ListPropertyDescriptor
|
|
933
|
|
934 class ListPropertyDescriptor : PropertyDescriptorWrapper
|
|
935 {
|
|
936 public ListPropertyDescriptor(PropertyDescriptor descriptor)
|
|
937 : base(descriptor)
|
|
938 {
|
|
939 }
|
|
940
|
|
941 public override object GetValue(object component)
|
|
942 {
|
|
943 var value = base.GetValue(component);
|
|
944
|
|
945 if (value == null)
|
|
946 return value;
|
|
947
|
|
948 if (value is IBindingList && value is ITypedList)
|
|
949 return value;
|
|
950
|
|
951 return EditableArrayList.Adapter((IList)value);
|
|
952 }
|
|
953 }
|
|
954
|
|
955 #endregion
|
|
956
|
|
957 #region StandardPropertyDescriptor
|
|
958
|
|
959 class StandardPropertyDescriptor : PropertyDescriptorWrapper
|
|
960 {
|
|
961 protected readonly PropertyDescriptor _descriptor;
|
|
962 protected readonly IsNullHandler _isNull;
|
|
963
|
|
964 protected readonly string _prefixedName;
|
|
965 protected readonly PropertyDescriptor[] _chainAccessors;
|
|
966
|
|
967 public StandardPropertyDescriptor(
|
|
968 PropertyDescriptor pd,
|
|
969 string namePrefix,
|
|
970 PropertyDescriptor[] chainAccessors,
|
|
971 IsNullHandler isNull)
|
|
972 : base(pd)
|
|
973 {
|
|
974 _descriptor = pd;
|
|
975 _isNull = isNull;
|
|
976 _prefixedName = namePrefix + pd.Name;
|
|
977 _chainAccessors = chainAccessors;
|
|
978 }
|
|
979
|
|
980 protected object GetNestedComponent(object component)
|
|
981 {
|
|
982 for (var i = 0;
|
|
983 i < _chainAccessors.Length && component != null && !(component is DBNull);
|
|
984 i++)
|
|
985 {
|
|
986 component = _chainAccessors[i].GetValue(component);
|
|
987 }
|
|
988
|
|
989 return component;
|
|
990 }
|
|
991
|
|
992 public override void SetValue(object component, object value)
|
|
993 {
|
|
994 component = GetNestedComponent(component);
|
|
995
|
|
996 if (component != null && !(component is DBNull))
|
|
997 _descriptor.SetValue(component, value);
|
|
998 }
|
|
999
|
|
1000 public override object GetValue(object component)
|
|
1001 {
|
|
1002 component = GetNestedComponent(component);
|
|
1003
|
|
1004 return CheckNull(
|
|
1005 component != null && !(component is DBNull)? _descriptor.GetValue(component): null);
|
|
1006 }
|
|
1007
|
|
1008 public override string Name
|
|
1009 {
|
|
1010 get { return _prefixedName; }
|
|
1011 }
|
|
1012
|
|
1013 protected object CheckNull(object value)
|
|
1014 {
|
|
1015 if (_isNull != null && _isNull(value))
|
|
1016 {
|
|
1017 switch (Common.Configuration.CheckNullReturnIfNull)
|
|
1018 {
|
|
1019 case Common.Configuration.NullEquivalent.DBNull:
|
|
1020 return DBNull.Value;
|
|
1021 case Common.Configuration.NullEquivalent.Null:
|
|
1022 return null;
|
|
1023 case Common.Configuration.NullEquivalent.Value:
|
|
1024 return value;
|
|
1025 }
|
|
1026
|
|
1027 return DBNull.Value;
|
|
1028 }
|
|
1029
|
|
1030 return value;
|
|
1031 }
|
|
1032 }
|
|
1033
|
|
1034 #endregion
|
|
1035
|
|
1036 #region objectViewPropertyDescriptor
|
|
1037
|
|
1038 class ObjectViewPropertyDescriptor : PropertyDescriptorWrapper
|
|
1039 {
|
|
1040 public ObjectViewPropertyDescriptor(PropertyDescriptor pd, IObjectView objectView)
|
|
1041 : base(pd)
|
|
1042 {
|
|
1043 _objectView = objectView;
|
|
1044 }
|
|
1045
|
|
1046 private readonly IObjectView _objectView;
|
|
1047
|
|
1048 public override object GetValue(object component)
|
|
1049 {
|
|
1050 _objectView.Object = component;
|
|
1051
|
|
1052 return base.GetValue(_objectView);
|
|
1053 }
|
|
1054
|
|
1055 public override void SetValue(object component, object value)
|
|
1056 {
|
|
1057 _objectView.Object = component;
|
|
1058
|
|
1059 base.SetValue(_objectView, value);
|
|
1060 }
|
|
1061 }
|
|
1062
|
|
1063 #endregion
|
|
1064
|
|
1065 #endregion
|
|
1066
|
|
1067 #region ITypeDescriptionProvider Members
|
|
1068
|
|
1069 string ITypeDescriptionProvider.ClassName
|
|
1070 {
|
|
1071 get { return OriginalType.Name; }
|
|
1072 }
|
|
1073
|
|
1074 string ITypeDescriptionProvider.ComponentName
|
|
1075 {
|
|
1076 get { return OriginalType.Name; }
|
|
1077 }
|
|
1078
|
|
1079 EventDescriptor ITypeDescriptionProvider.GetEvent(string name)
|
|
1080 {
|
|
1081 return new CustomEventDescriptor(OriginalType.GetEvent(name));
|
|
1082 }
|
|
1083
|
|
1084 PropertyDescriptor ITypeDescriptionProvider.GetProperty(string name)
|
|
1085 {
|
|
1086 var ma = this[name];
|
|
1087 return ma != null ? ma.PropertyDescriptor : null;
|
|
1088 }
|
|
1089
|
|
1090 AttributeCollection ITypeDescriptionProvider.GetAttributes()
|
|
1091 {
|
|
1092 var attributesAsObj = new TypeHelper(OriginalType).GetAttributes();
|
|
1093 var attributes = new Attribute[attributesAsObj.Length];
|
|
1094
|
|
1095 for (var i = 0; i < attributesAsObj.Length; i++)
|
|
1096 attributes[i] = attributesAsObj[i] as Attribute;
|
|
1097
|
|
1098 return new AttributeCollection(attributes);
|
|
1099 }
|
|
1100
|
|
1101 EventDescriptorCollection ITypeDescriptionProvider.GetEvents()
|
|
1102 {
|
|
1103 var ei = OriginalType.GetEvents();
|
|
1104 var ed = new EventDescriptor[ei.Length];
|
|
1105
|
|
1106 for (var i = 0; i < ei.Length; i++)
|
|
1107 ed[i] = new CustomEventDescriptor(ei[i]);
|
|
1108
|
|
1109 return new EventDescriptorCollection(ed);
|
|
1110 }
|
|
1111
|
|
1112 PropertyDescriptorCollection ITypeDescriptionProvider.GetProperties()
|
|
1113 {
|
|
1114 return CreatePropertyDescriptors();
|
|
1115 }
|
|
1116
|
|
1117 #region CustomEventDescriptor
|
|
1118
|
|
1119 class CustomEventDescriptor : EventDescriptor
|
|
1120 {
|
|
1121 public CustomEventDescriptor(EventInfo eventInfo)
|
|
1122 : base(eventInfo.Name, null)
|
|
1123 {
|
|
1124 _eventInfo = eventInfo;
|
|
1125 }
|
|
1126
|
|
1127 private readonly EventInfo _eventInfo;
|
|
1128
|
|
1129 public override void AddEventHandler(object component, Delegate value)
|
|
1130 {
|
|
1131 _eventInfo.AddEventHandler(component, value);
|
|
1132 }
|
|
1133
|
|
1134 public override void RemoveEventHandler(object component, Delegate value)
|
|
1135 {
|
|
1136 _eventInfo.RemoveEventHandler(component, value);
|
|
1137 }
|
|
1138
|
|
1139 public override Type ComponentType { get { return _eventInfo.DeclaringType; } }
|
|
1140 public override Type EventType { get { return _eventInfo.EventHandlerType; } }
|
|
1141 public override bool IsMulticast { get { return _eventInfo.IsMulticast; } }
|
|
1142 }
|
|
1143
|
|
1144 #endregion
|
|
1145
|
|
1146 #endregion
|
|
1147
|
|
1148 #endif
|
|
1149
|
|
1150 #endregion
|
|
1151 }
|
|
1152 }
|