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 }