2 // System.ComponentModel.TypeDescriptor.cs
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 // (C) 2002 Ximian, Inc (http://www.ximian.com)
9 // (C) 2003 Andreas Nahr
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
35 using System.Reflection;
36 using System.Globalization;
37 using System.ComponentModel.Design;
39 namespace System.ComponentModel
42 public sealed class TypeDescriptor
44 private static readonly object creatingDefaultConverters = new object ();
45 private static Hashtable defaultConverters;
46 private static IComNativeDescriptorHandler descriptorHandler;
47 private static Hashtable componentTable = new Hashtable ();
48 private static Hashtable typeTable = new Hashtable ();
50 private TypeDescriptor ()
55 public static void AddEditorTable (Type editorBaseType, Hashtable table)
57 throw new NotImplementedException ();
60 public static IDesigner CreateDesigner(IComponent component, Type designerBaseType)
62 string tn = designerBaseType.AssemblyQualifiedName;
63 AttributeCollection col = GetAttributes (component);
65 foreach (Attribute at in col) {
66 DesignerAttribute dat = at as DesignerAttribute;
67 if (dat != null && tn == dat.DesignerBaseTypeName) {
68 return (IDesigner) Activator.CreateInstance (GetTypeFromName (component, dat.DesignerTypeName));
75 public static EventDescriptor CreateEvent (Type componentType,
78 Attribute [] attributes)
80 return new ReflectionEventDescriptor (componentType, name, type, attributes);
83 public static EventDescriptor CreateEvent (Type componentType,
84 EventDescriptor oldEventDescriptor,
85 Attribute [] attributes)
87 return new ReflectionEventDescriptor (componentType, oldEventDescriptor, attributes);
90 public static PropertyDescriptor CreateProperty (Type componentType,
93 Attribute [] attributes)
95 return new ReflectionPropertyDescriptor (componentType, name, type, attributes);
98 public static PropertyDescriptor CreateProperty (Type componentType,
99 PropertyDescriptor oldPropertyDescriptor,
100 Attribute [] attributes)
102 return new ReflectionPropertyDescriptor (componentType, oldPropertyDescriptor, attributes);
105 public static AttributeCollection GetAttributes (Type componentType)
107 if (componentType == null)
108 return AttributeCollection.Empty;
110 return GetTypeInfo (componentType).GetAttributes ();
113 public static AttributeCollection GetAttributes (object component)
115 return GetAttributes (component, false);
118 public static AttributeCollection GetAttributes (object component, bool noCustomTypeDesc)
120 if (component == null)
121 return AttributeCollection.Empty;
123 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
124 return ((ICustomTypeDescriptor) component).GetAttributes ();
126 IComponent com = component as IComponent;
128 return GetComponentInfo (com).GetAttributes ();
130 return GetTypeInfo (component.GetType()).GetAttributes ();
134 public static string GetClassName (object component)
136 return GetClassName (component, false);
139 public static string GetClassName (object component, bool noCustomTypeDesc)
141 if (component == null)
142 throw new ArgumentNullException ("component", "component cannot be null");
144 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
145 String res = ((ICustomTypeDescriptor) component).GetClassName ();
147 res = ((ICustomTypeDescriptor) component).GetComponentName ();
149 res = component.GetType ().FullName;
152 return component.GetType ().FullName;
156 public static string GetComponentName (object component)
158 return GetComponentName (component, false);
161 public static string GetComponentName (object component, bool noCustomTypeDesc)
163 if (component == null)
164 throw new ArgumentNullException ("component", "component cannot be null");
166 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
167 return ((ICustomTypeDescriptor) component).GetComponentName ();
169 IComponent c = component as IComponent;
170 if (c != null && c.Site != null)
175 return component.GetType().Name;
180 public static TypeConverter GetConverter (object component)
182 return GetConverter (component, false);
185 public static TypeConverter GetConverter (object component, bool noCustomTypeDesc)
187 if (component == null)
188 throw new ArgumentNullException ("component", "component cannot be null");
190 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
191 return ((ICustomTypeDescriptor) component).GetConverter ();
195 AttributeCollection atts = GetAttributes (component, false);
196 TypeConverterAttribute tca = (TypeConverterAttribute) atts[typeof(TypeConverterAttribute)];
197 if (tca != null && tca.ConverterTypeName.Length > 0) {
198 t = GetTypeFromName (component as IComponent, tca.ConverterTypeName);
202 ConstructorInfo ci = t.GetConstructor (new Type[] { typeof(Type) });
204 return (TypeConverter) ci.Invoke (new object[] { component.GetType () });
206 return (TypeConverter) Activator.CreateInstance (t);
209 return GetConverter (component.GetType ());
213 private static Hashtable DefaultConverters
216 lock (creatingDefaultConverters) {
217 if (defaultConverters != null)
218 return defaultConverters;
220 defaultConverters = new Hashtable ();
221 defaultConverters.Add (typeof (bool), typeof (BooleanConverter));
222 defaultConverters.Add (typeof (byte), typeof (ByteConverter));
223 defaultConverters.Add (typeof (sbyte), typeof (SByteConverter));
224 defaultConverters.Add (typeof (string), typeof (StringConverter));
225 defaultConverters.Add (typeof (char), typeof (CharConverter));
226 defaultConverters.Add (typeof (short), typeof (Int16Converter));
227 defaultConverters.Add (typeof (int), typeof (Int32Converter));
228 defaultConverters.Add (typeof (long), typeof (Int64Converter));
229 defaultConverters.Add (typeof (ushort), typeof (UInt16Converter));
230 defaultConverters.Add (typeof (uint), typeof (UInt32Converter));
231 defaultConverters.Add (typeof (ulong), typeof (UInt64Converter));
232 defaultConverters.Add (typeof (float), typeof (SingleConverter));
233 defaultConverters.Add (typeof (double), typeof (DoubleConverter));
234 defaultConverters.Add (typeof (decimal), typeof (DecimalConverter));
235 defaultConverters.Add (typeof (object), typeof (TypeConverter));
236 defaultConverters.Add (typeof (void), typeof (TypeConverter));
237 defaultConverters.Add (typeof (Array), typeof (ArrayConverter));
238 defaultConverters.Add (typeof (CultureInfo), typeof (CultureInfoConverter));
239 defaultConverters.Add (typeof (DateTime), typeof (DateTimeConverter));
240 defaultConverters.Add (typeof (Guid), typeof (GuidConverter));
241 defaultConverters.Add (typeof (TimeSpan), typeof (TimeSpanConverter));
242 defaultConverters.Add (typeof (ICollection), typeof (CollectionConverter));
244 return defaultConverters;
248 public static TypeConverter GetConverter (Type type)
250 TypeConverterAttribute tca = null;
252 object [] atts = type.GetCustomAttributes (typeof(TypeConverterAttribute), true);
255 tca = (TypeConverterAttribute)atts[0];
258 t = GetTypeFromName (null, tca.ConverterTypeName);
263 // EnumConverter needs to know the enum type
264 return new EnumConverter(type);
265 } else if (type.IsArray) {
266 return new ArrayConverter ();
271 t = FindConverterType (type);
274 Exception exc = null;
276 return (TypeConverter) Activator.CreateInstance (t);
277 } catch (MissingMethodException e) {
282 return (TypeConverter) Activator.CreateInstance (t, new object [] {type});
283 } catch (MissingMethodException e) {
288 return new ReferenceConverter (type); // Default?
291 private static Type FindConverterType (Type type)
295 // Is there a default converter
296 t = (Type) DefaultConverters [type];
300 // Find default converter with a type this type is assignable to
301 foreach (Type defType in DefaultConverters.Keys) {
302 if (defType.IsInterface && defType.IsAssignableFrom (type)) {
303 return (Type) DefaultConverters [defType];
307 // Nothing found, try the same with our base type
308 if (type.BaseType != null)
309 return FindConverterType (type.BaseType);
314 public static EventDescriptor GetDefaultEvent (Type componentType)
316 return GetTypeInfo (componentType).GetDefaultEvent ();
319 public static EventDescriptor GetDefaultEvent (object component)
321 return GetDefaultEvent (component, false);
324 public static EventDescriptor GetDefaultEvent (object component, bool noCustomTypeDesc)
326 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
327 return ((ICustomTypeDescriptor) component).GetDefaultEvent ();
329 IComponent com = component as IComponent;
331 return GetComponentInfo (com).GetDefaultEvent ();
333 return GetTypeInfo (component.GetType()).GetDefaultEvent ();
337 public static PropertyDescriptor GetDefaultProperty (Type componentType)
339 return GetTypeInfo (componentType).GetDefaultProperty ();
342 public static PropertyDescriptor GetDefaultProperty (object component)
344 return GetDefaultProperty (component, false);
347 public static PropertyDescriptor GetDefaultProperty (object component, bool noCustomTypeDesc)
349 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
350 return ((ICustomTypeDescriptor) component).GetDefaultProperty ();
352 IComponent com = component as IComponent;
354 return GetComponentInfo (com).GetDefaultProperty ();
356 return GetTypeInfo (component.GetType()).GetDefaultProperty ();
360 public static object GetEditor (Type componentType, Type editorBaseType)
363 object [] atts = componentType.GetCustomAttributes (typeof(EditorAttribute), true);
364 if (atts == null || atts.Length == 0)
368 foreach (EditorAttribute ea in atts)
370 t = GetTypeFromName (null, ea.EditorTypeName);
371 if (t.IsSubclassOf(editorBaseType))
376 Exception exc = null;
378 return Activator.CreateInstance (t);
379 } catch (MissingMethodException e) {
384 return Activator.CreateInstance (t, new object [] {componentType});
385 } catch (MissingMethodException e) {
390 return null; // No editor specified
393 public static object GetEditor (object component, Type editorBaseType)
395 return GetEditor (component, editorBaseType, false);
399 public static object GetEditor (object component, Type editorBaseType, bool noCustomTypeDesc)
401 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
402 return ((ICustomTypeDescriptor) component).GetEditor (editorBaseType);
403 throw new NotImplementedException ();
406 public static EventDescriptorCollection GetEvents (object component)
408 return GetEvents (component, false);
411 public static EventDescriptorCollection GetEvents (Type componentType)
413 return GetEvents (componentType, null);
416 public static EventDescriptorCollection GetEvents (object component, Attribute [] attributes)
418 return GetEvents (component, attributes, false);
421 public static EventDescriptorCollection GetEvents (object component, bool noCustomTypeDesc)
423 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
424 return ((ICustomTypeDescriptor) component).GetEvents ();
426 IComponent com = component as IComponent;
428 return GetComponentInfo (com).GetEvents ();
430 return GetTypeInfo (component.GetType()).GetEvents ();
434 public static EventDescriptorCollection GetEvents (Type componentType, Attribute [] attributes)
436 return GetTypeInfo (componentType).GetEvents (attributes);
439 public static EventDescriptorCollection GetEvents (object component, Attribute [] attributes, bool noCustomTypeDesc)
441 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
442 return ((ICustomTypeDescriptor) component).GetEvents (attributes);
444 IComponent com = component as IComponent;
446 return GetComponentInfo (com).GetEvents (attributes);
448 return GetTypeInfo (component.GetType()).GetEvents (attributes);
452 public static PropertyDescriptorCollection GetProperties (object component)
454 return GetProperties (component, false);
457 public static PropertyDescriptorCollection GetProperties (Type componentType)
459 return GetProperties (componentType, null);
462 public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes)
464 return GetProperties (component, attributes, false);
467 public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes, bool noCustomTypeDesc)
469 if (component == null)
470 return PropertyDescriptorCollection.Empty;
472 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
473 return ((ICustomTypeDescriptor) component).GetProperties (attributes);
475 IComponent com = component as IComponent;
477 return GetComponentInfo (com).GetProperties (attributes);
479 return GetTypeInfo (component.GetType()).GetProperties (attributes);
483 public static PropertyDescriptorCollection GetProperties (object component, bool noCustomTypeDesc)
485 if (component == null)
486 return PropertyDescriptorCollection.Empty;
488 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
489 return ((ICustomTypeDescriptor) component).GetProperties ();
491 IComponent com = component as IComponent;
493 return GetComponentInfo (com).GetProperties ();
495 return GetTypeInfo (component.GetType()).GetProperties ();
499 public static PropertyDescriptorCollection GetProperties (Type componentType, Attribute [] attributes)
501 return GetTypeInfo (componentType).GetProperties (attributes);
504 public static void SortDescriptorArray (IList infos)
506 string[] names = new string [infos.Count];
507 object[] values = new object [infos.Count];
508 for (int n=0; n<names.Length; n++) {
509 names[n] = ((MemberDescriptor)infos[n]).Name;
510 values[n] = infos[n];
512 Array.Sort (names, values);
514 foreach (object ob in values)
518 public static IComNativeDescriptorHandler ComNativeDescriptorHandler {
519 get { return descriptorHandler; }
520 set { descriptorHandler = value; }
523 public static void Refresh (Assembly assembly)
525 foreach (Type type in assembly.GetTypes())
529 public static void Refresh (Module module)
531 foreach (Type type in module.GetTypes())
535 public static void Refresh (object component)
537 lock (componentTable)
539 componentTable.Remove (component);
541 if (Refreshed != null) Refreshed (new RefreshEventArgs (component));
544 public static void Refresh (Type type)
548 typeTable.Remove (type);
550 if (Refreshed != null) Refreshed (new RefreshEventArgs (type));
553 static EventHandler onDispose;
555 static void OnComponentDisposed (object sender, EventArgs args)
557 lock (componentTable) {
558 componentTable.Remove (sender);
562 public static event RefreshEventHandler Refreshed;
564 internal static ComponentInfo GetComponentInfo (IComponent com)
566 lock (componentTable)
568 ComponentInfo ci = (ComponentInfo) componentTable [com];
570 if (onDispose == null)
571 onDispose = new EventHandler (OnComponentDisposed);
573 com.Disposed += onDispose;
574 ci = new ComponentInfo (com);
575 componentTable [com] = ci;
581 internal static TypeInfo GetTypeInfo (Type type)
585 TypeInfo ci = (TypeInfo) typeTable [type];
587 ci = new TypeInfo (type);
588 typeTable [type] = ci;
594 static Type GetTypeFromName (IComponent component, string typeName)
596 if (component != null && component.Site != null) {
597 ITypeResolutionService resver = (ITypeResolutionService) component.Site.GetService (typeof(ITypeResolutionService));
598 if (resver != null) return resver.GetType (typeName, true, false);
601 Type t = Type.GetType (typeName);
602 if (t == null) throw new ArgumentException ("Type '" + typeName + "' not found");
607 internal abstract class Info
610 EventDescriptor _defaultEvent;
611 bool _gotDefaultEvent;
612 PropertyDescriptor _defaultProperty;
613 bool _gotDefaultProperty;
614 AttributeCollection _attributes;
616 public Info (Type infoType)
618 _infoType = infoType;
621 public abstract AttributeCollection GetAttributes ();
622 public abstract EventDescriptorCollection GetEvents ();
623 public abstract PropertyDescriptorCollection GetProperties ();
627 get { return _infoType; }
630 public EventDescriptorCollection GetEvents (Attribute[] attributes)
632 EventDescriptorCollection evs = GetEvents ();
633 if (attributes == null) return evs;
634 else return evs.Filter (attributes);
637 public PropertyDescriptorCollection GetProperties (Attribute[] attributes)
639 PropertyDescriptorCollection props = GetProperties ();
640 if (attributes == null) return props;
641 else return props.Filter (attributes);
644 public EventDescriptor GetDefaultEvent ()
646 if (_gotDefaultEvent) return _defaultEvent;
648 DefaultEventAttribute attr = (DefaultEventAttribute) GetAttributes()[typeof(DefaultEventAttribute)];
649 if (attr == null || attr.Name == null)
650 _defaultEvent = null;
652 EventDescriptorCollection events = GetEvents ();
653 _defaultEvent = events [attr.Name];
655 // In our test case (TypeDescriptorTest.TestGetDefaultEvent), we have
656 // a scenario where a custom filter adds the DefaultEventAttribute,
657 // but its FilterEvents method removes the event the
658 // DefaultEventAttribute applied to. .NET 1.x accepts this and returns
659 // the *other* event defined in the class.
661 // Consequently, we know we have a DefaultEvent, but we need to check
662 // and ensure that the requested event is unfiltered. If it is, just
663 // grab the first element in the collection.
664 if (_defaultEvent == null && events.Count > 0)
665 _defaultEvent = events [0];
668 _gotDefaultEvent = true;
669 return _defaultEvent;
672 public PropertyDescriptor GetDefaultProperty ()
674 if (_gotDefaultProperty) return _defaultProperty;
676 DefaultPropertyAttribute attr = (DefaultPropertyAttribute) GetAttributes()[typeof(DefaultPropertyAttribute)];
677 if (attr == null || attr.Name == null)
678 _defaultProperty = null;
680 PropertyDescriptorCollection properties = GetProperties ();
681 _defaultProperty = properties[attr.Name];
683 _gotDefaultProperty = true;
684 return _defaultProperty;
687 protected AttributeCollection GetAttributes (IComponent comp)
689 if (_attributes != null) return _attributes;
692 object[] ats = _infoType.GetCustomAttributes (true);
693 Hashtable t = new Hashtable ();
694 foreach (Attribute at in ats)
697 if (comp != null && comp.Site != null)
699 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) comp.Site.GetService (typeof(ITypeDescriptorFilterService));
700 cache = filter.FilterAttributes (comp, t);
703 ArrayList atts = new ArrayList ();
704 atts.AddRange (t.Values);
705 AttributeCollection attCol = new AttributeCollection (atts);
706 if (cache) _attributes = attCol;
711 internal class ComponentInfo : Info
713 IComponent _component;
714 EventDescriptorCollection _events;
715 PropertyDescriptorCollection _properties;
717 public ComponentInfo (IComponent component): base (component.GetType())
719 _component = component;
722 public override AttributeCollection GetAttributes ()
724 return base.GetAttributes (_component);
727 public override EventDescriptorCollection GetEvents ()
729 if (_events != null) return _events;
732 EventInfo[] events = _component.GetType().GetEvents ();
733 Hashtable t = new Hashtable ();
734 foreach (EventInfo ev in events)
735 t [ev.Name] = new ReflectionEventDescriptor (ev);
737 if (_component.Site != null)
739 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) _component.Site.GetService (typeof(ITypeDescriptorFilterService));
740 cache = filter.FilterEvents (_component, t);
743 ArrayList atts = new ArrayList ();
744 atts.AddRange (t.Values);
745 EventDescriptorCollection attCol = new EventDescriptorCollection (atts);
746 if (cache) _events = attCol;
750 public override PropertyDescriptorCollection GetProperties ()
752 if (_properties != null) return _properties;
755 PropertyInfo[] props = _component.GetType().GetProperties ();
756 Hashtable t = new Hashtable ();
757 foreach (PropertyInfo pr in props)
758 t [pr.Name] = new ReflectionPropertyDescriptor (pr);
760 if (_component.Site != null)
762 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) _component.Site.GetService (typeof(ITypeDescriptorFilterService));
763 cache = filter.FilterProperties (_component, t);
766 PropertyDescriptor[] descriptors = new PropertyDescriptor[t.Values.Count];
767 t.Values.CopyTo (descriptors, 0);
768 PropertyDescriptorCollection attCol = new PropertyDescriptorCollection (descriptors, true);
769 if (cache) _properties = attCol;
774 internal class TypeInfo : Info
776 EventDescriptorCollection _events;
777 PropertyDescriptorCollection _properties;
779 public TypeInfo (Type t): base (t)
783 public override AttributeCollection GetAttributes ()
785 return base.GetAttributes (null);
788 public override EventDescriptorCollection GetEvents ()
790 if (_events != null) return _events;
792 EventInfo[] events = InfoType.GetEvents ();
793 EventDescriptor[] descs = new EventDescriptor [events.Length];
794 for (int n=0; n<events.Length; n++)
795 descs [n] = new ReflectionEventDescriptor (events[n]);
797 _events = new EventDescriptorCollection (descs);
801 public override PropertyDescriptorCollection GetProperties ()
803 if (_properties != null) return _properties;
805 PropertyInfo[] props = InfoType.GetProperties ();
806 PropertyDescriptor[] descs = new PropertyDescriptor [props.Length];
807 for (int n=0; n<props.Length; n++)
808 descs [n] = new ReflectionPropertyDescriptor (props[n]);
810 _properties = new PropertyDescriptorCollection (descs, true);