Mercurial > pub > bltoolkit
comparison Source/Reflection/TypeAccessor.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f990fcb411a9 |
---|---|
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 } |