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.
33 using System.Collections;
34 using System.Reflection;
35 using System.Globalization;
36 using System.ComponentModel.Design;
37 using System.Security.Permissions;
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 [ReflectionPermission (SecurityAction.LinkDemand, TypeInformation = true, MemberAccess = true)]
76 public static EventDescriptor CreateEvent (Type componentType,
79 Attribute [] attributes)
81 return new ReflectionEventDescriptor (componentType, name, type, attributes);
84 [ReflectionPermission (SecurityAction.LinkDemand, TypeInformation = true, MemberAccess = true)]
85 public static EventDescriptor CreateEvent (Type componentType,
86 EventDescriptor oldEventDescriptor,
87 Attribute [] attributes)
89 return new ReflectionEventDescriptor (componentType, oldEventDescriptor, attributes);
92 [ReflectionPermission (SecurityAction.LinkDemand, TypeInformation = true, MemberAccess = true)]
93 public static PropertyDescriptor CreateProperty (Type componentType,
96 Attribute [] attributes)
98 return new ReflectionPropertyDescriptor (componentType, name, type, attributes);
101 [ReflectionPermission (SecurityAction.LinkDemand, TypeInformation = true, MemberAccess = true)]
102 public static PropertyDescriptor CreateProperty (Type componentType,
103 PropertyDescriptor oldPropertyDescriptor,
104 Attribute [] attributes)
106 return new ReflectionPropertyDescriptor (componentType, oldPropertyDescriptor, attributes);
109 public static AttributeCollection GetAttributes (Type componentType)
111 if (componentType == null)
112 return AttributeCollection.Empty;
114 return GetTypeInfo (componentType).GetAttributes ();
117 public static AttributeCollection GetAttributes (object component)
119 return GetAttributes (component, false);
122 public static AttributeCollection GetAttributes (object component, bool noCustomTypeDesc)
124 if (component == null)
125 return AttributeCollection.Empty;
127 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
128 return ((ICustomTypeDescriptor) component).GetAttributes ();
130 IComponent com = component as IComponent;
131 if (com != null && com.Site != null)
132 return GetComponentInfo (com).GetAttributes ();
134 return GetTypeInfo (component.GetType()).GetAttributes ();
138 public static string GetClassName (object component)
140 return GetClassName (component, false);
143 public static string GetClassName (object component, bool noCustomTypeDesc)
145 if (component == null)
146 throw new ArgumentNullException ("component", "component cannot be null");
148 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
149 String res = ((ICustomTypeDescriptor) component).GetClassName ();
151 res = ((ICustomTypeDescriptor) component).GetComponentName ();
153 res = component.GetType ().FullName;
156 return component.GetType ().FullName;
160 public static string GetComponentName (object component)
162 return GetComponentName (component, false);
165 public static string GetComponentName (object component, bool noCustomTypeDesc)
167 if (component == null)
168 throw new ArgumentNullException ("component", "component cannot be null");
170 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
171 return ((ICustomTypeDescriptor) component).GetComponentName ();
173 IComponent c = component as IComponent;
174 if (c != null && c.Site != null)
179 return component.GetType().Name;
184 public static TypeConverter GetConverter (object component)
186 return GetConverter (component, false);
189 public static TypeConverter GetConverter (object component, bool noCustomTypeDesc)
191 if (component == null)
192 throw new ArgumentNullException ("component", "component cannot be null");
194 if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) {
195 return ((ICustomTypeDescriptor) component).GetConverter ();
199 AttributeCollection atts = GetAttributes (component, false);
200 TypeConverterAttribute tca = (TypeConverterAttribute) atts[typeof(TypeConverterAttribute)];
201 if (tca != null && tca.ConverterTypeName.Length > 0) {
202 t = GetTypeFromName (component as IComponent, tca.ConverterTypeName);
206 ConstructorInfo ci = t.GetConstructor (new Type[] { typeof(Type) });
208 return (TypeConverter) ci.Invoke (new object[] { component.GetType () });
210 return (TypeConverter) Activator.CreateInstance (t);
213 return GetConverter (component.GetType ());
217 private static Hashtable DefaultConverters
220 lock (creatingDefaultConverters) {
221 if (defaultConverters != null)
222 return defaultConverters;
224 defaultConverters = new Hashtable ();
225 defaultConverters.Add (typeof (bool), typeof (BooleanConverter));
226 defaultConverters.Add (typeof (byte), typeof (ByteConverter));
227 defaultConverters.Add (typeof (sbyte), typeof (SByteConverter));
228 defaultConverters.Add (typeof (string), typeof (StringConverter));
229 defaultConverters.Add (typeof (char), typeof (CharConverter));
230 defaultConverters.Add (typeof (short), typeof (Int16Converter));
231 defaultConverters.Add (typeof (int), typeof (Int32Converter));
232 defaultConverters.Add (typeof (long), typeof (Int64Converter));
233 defaultConverters.Add (typeof (ushort), typeof (UInt16Converter));
234 defaultConverters.Add (typeof (uint), typeof (UInt32Converter));
235 defaultConverters.Add (typeof (ulong), typeof (UInt64Converter));
236 defaultConverters.Add (typeof (float), typeof (SingleConverter));
237 defaultConverters.Add (typeof (double), typeof (DoubleConverter));
238 defaultConverters.Add (typeof (decimal), typeof (DecimalConverter));
239 defaultConverters.Add (typeof (object), typeof (TypeConverter));
240 defaultConverters.Add (typeof (void), typeof (TypeConverter));
241 defaultConverters.Add (typeof (Array), typeof (ArrayConverter));
242 defaultConverters.Add (typeof (CultureInfo), typeof (CultureInfoConverter));
243 defaultConverters.Add (typeof (DateTime), typeof (DateTimeConverter));
244 defaultConverters.Add (typeof (Guid), typeof (GuidConverter));
245 defaultConverters.Add (typeof (TimeSpan), typeof (TimeSpanConverter));
246 defaultConverters.Add (typeof (ICollection), typeof (CollectionConverter));
248 return defaultConverters;
252 public static TypeConverter GetConverter (Type type)
254 TypeConverterAttribute tca = null;
256 object [] atts = type.GetCustomAttributes (typeof(TypeConverterAttribute), true);
259 tca = (TypeConverterAttribute)atts[0];
262 t = GetTypeFromName (null, tca.ConverterTypeName);
267 // EnumConverter needs to know the enum type
268 return new EnumConverter(type);
269 } else if (type.IsArray) {
270 return new ArrayConverter ();
275 t = FindConverterType (type);
278 Exception exc = null;
280 return (TypeConverter) Activator.CreateInstance (t);
281 } catch (MissingMethodException e) {
286 return (TypeConverter) Activator.CreateInstance (t, new object [] {type});
287 } catch (MissingMethodException e) {
292 return new ReferenceConverter (type); // Default?
295 private static Type FindConverterType (Type type)
299 // Is there a default converter
300 t = (Type) DefaultConverters [type];
304 // Find default converter with a type this type is assignable to
305 foreach (Type defType in DefaultConverters.Keys) {
306 if (defType.IsInterface && defType.IsAssignableFrom (type)) {
307 return (Type) DefaultConverters [defType];
311 // Nothing found, try the same with our base type
312 if (type.BaseType != null)
313 return FindConverterType (type.BaseType);
318 public static EventDescriptor GetDefaultEvent (Type componentType)
320 return GetTypeInfo (componentType).GetDefaultEvent ();
323 public static EventDescriptor GetDefaultEvent (object component)
325 return GetDefaultEvent (component, false);
328 public static EventDescriptor GetDefaultEvent (object component, bool noCustomTypeDesc)
330 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
331 return ((ICustomTypeDescriptor) component).GetDefaultEvent ();
333 IComponent com = component as IComponent;
334 if (com != null && com.Site != null)
335 return GetComponentInfo (com).GetDefaultEvent ();
337 return GetTypeInfo (component.GetType()).GetDefaultEvent ();
341 public static PropertyDescriptor GetDefaultProperty (Type componentType)
343 return GetTypeInfo (componentType).GetDefaultProperty ();
346 public static PropertyDescriptor GetDefaultProperty (object component)
348 return GetDefaultProperty (component, false);
351 public static PropertyDescriptor GetDefaultProperty (object component, bool noCustomTypeDesc)
353 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
354 return ((ICustomTypeDescriptor) component).GetDefaultProperty ();
356 IComponent com = component as IComponent;
357 if (com != null && com.Site != null)
358 return GetComponentInfo (com).GetDefaultProperty ();
360 return GetTypeInfo (component.GetType()).GetDefaultProperty ();
364 public static object GetEditor (Type componentType, Type editorBaseType)
367 object [] atts = componentType.GetCustomAttributes (typeof(EditorAttribute), true);
368 if (atts == null || atts.Length == 0)
372 foreach (EditorAttribute ea in atts)
374 t = GetTypeFromName (null, ea.EditorTypeName);
375 if (t.IsSubclassOf(editorBaseType))
380 Exception exc = null;
382 return Activator.CreateInstance (t);
383 } catch (MissingMethodException e) {
388 return Activator.CreateInstance (t, new object [] {componentType});
389 } catch (MissingMethodException e) {
394 return null; // No editor specified
397 public static object GetEditor (object component, Type editorBaseType)
399 return GetEditor (component, editorBaseType, false);
402 public static object GetEditor (object component, Type editorBaseType, bool noCustomTypeDesc)
404 if (component == null)
405 throw new ArgumentNullException ("component");
406 if (editorBaseType == null)
407 throw new ArgumentNullException ("editorBaseType");
409 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
410 return ((ICustomTypeDescriptor) component).GetEditor (editorBaseType);
412 object [] atts = component.GetType ().GetCustomAttributes (typeof (EditorAttribute), true);
413 if (atts.Length == 0)
415 string target = editorBaseType.AssemblyQualifiedName;
417 foreach (EditorAttribute ea in atts){
418 if (ea.EditorBaseTypeName == target){
419 Type t = Type.GetType (ea.EditorTypeName, true);
421 return Activator.CreateInstance (t);
427 public static EventDescriptorCollection GetEvents (object component)
429 return GetEvents (component, false);
432 public static EventDescriptorCollection GetEvents (Type componentType)
434 return GetEvents (componentType, null);
437 public static EventDescriptorCollection GetEvents (object component, Attribute [] attributes)
439 return GetEvents (component, attributes, false);
442 public static EventDescriptorCollection GetEvents (object component, bool noCustomTypeDesc)
444 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
445 return ((ICustomTypeDescriptor) component).GetEvents ();
447 IComponent com = component as IComponent;
448 if (com != null && com.Site != null)
449 return GetComponentInfo (com).GetEvents ();
451 return GetTypeInfo (component.GetType()).GetEvents ();
455 public static EventDescriptorCollection GetEvents (Type componentType, Attribute [] attributes)
457 return GetTypeInfo (componentType).GetEvents (attributes);
460 public static EventDescriptorCollection GetEvents (object component, Attribute [] attributes, bool noCustomTypeDesc)
462 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
463 return ((ICustomTypeDescriptor) component).GetEvents (attributes);
465 IComponent com = component as IComponent;
466 if (com != null && com.Site != null)
467 return GetComponentInfo (com).GetEvents (attributes);
469 return GetTypeInfo (component.GetType()).GetEvents (attributes);
473 public static PropertyDescriptorCollection GetProperties (object component)
475 return GetProperties (component, false);
478 public static PropertyDescriptorCollection GetProperties (Type componentType)
480 return GetProperties (componentType, null);
483 public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes)
485 return GetProperties (component, attributes, false);
488 public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes, bool noCustomTypeDesc)
490 if (component == null)
491 return PropertyDescriptorCollection.Empty;
493 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
494 return ((ICustomTypeDescriptor) component).GetProperties (attributes);
496 IComponent com = component as IComponent;
497 if (com != null && com.Site != null)
498 return GetComponentInfo (com).GetProperties (attributes);
500 return GetTypeInfo (component.GetType()).GetProperties (attributes);
504 public static PropertyDescriptorCollection GetProperties (object component, bool noCustomTypeDesc)
506 if (component == null)
507 return PropertyDescriptorCollection.Empty;
509 if (!noCustomTypeDesc && (component is ICustomTypeDescriptor))
510 return ((ICustomTypeDescriptor) component).GetProperties ();
512 IComponent com = component as IComponent;
513 if (com != null && com.Site != null)
514 return GetComponentInfo (com).GetProperties ();
516 return GetTypeInfo (component.GetType()).GetProperties ();
520 public static PropertyDescriptorCollection GetProperties (Type componentType, Attribute [] attributes)
522 return GetTypeInfo (componentType).GetProperties (attributes);
525 public static void SortDescriptorArray (IList infos)
527 string[] names = new string [infos.Count];
528 object[] values = new object [infos.Count];
529 for (int n=0; n<names.Length; n++) {
530 names[n] = ((MemberDescriptor)infos[n]).Name;
531 values[n] = infos[n];
533 Array.Sort (names, values);
535 foreach (object ob in values)
539 public static IComNativeDescriptorHandler ComNativeDescriptorHandler {
540 [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
541 get { return descriptorHandler; }
542 [PermissionSet (SecurityAction.LinkDemand, Unrestricted = true)]
543 set { descriptorHandler = value; }
546 public static void Refresh (Assembly assembly)
548 foreach (Type type in assembly.GetTypes())
552 public static void Refresh (Module module)
554 foreach (Type type in module.GetTypes())
558 public static void Refresh (object component)
560 lock (componentTable)
562 componentTable.Remove (component);
564 if (Refreshed != null) Refreshed (new RefreshEventArgs (component));
567 public static void Refresh (Type type)
571 typeTable.Remove (type);
573 if (Refreshed != null) Refreshed (new RefreshEventArgs (type));
576 static EventHandler onDispose;
578 static void OnComponentDisposed (object sender, EventArgs args)
580 lock (componentTable) {
581 componentTable.Remove (sender);
585 public static event RefreshEventHandler Refreshed;
587 internal static ComponentInfo GetComponentInfo (IComponent com)
589 lock (componentTable)
591 ComponentInfo ci = (ComponentInfo) componentTable [com];
593 if (onDispose == null)
594 onDispose = new EventHandler (OnComponentDisposed);
596 com.Disposed += onDispose;
597 ci = new ComponentInfo (com);
598 componentTable [com] = ci;
604 internal static TypeInfo GetTypeInfo (Type type)
608 TypeInfo ci = (TypeInfo) typeTable [type];
610 ci = new TypeInfo (type);
611 typeTable [type] = ci;
617 static Type GetTypeFromName (IComponent component, string typeName)
619 if (component != null && component.Site != null) {
620 ITypeResolutionService resver = (ITypeResolutionService) component.Site.GetService (typeof(ITypeResolutionService));
622 return resver.GetType (typeName, true, false);
625 Type t = Type.GetType (typeName);
626 if (t == null) throw new ArgumentException ("Type '" + typeName + "' not found");
631 internal abstract class Info
634 EventDescriptor _defaultEvent;
635 bool _gotDefaultEvent;
636 PropertyDescriptor _defaultProperty;
637 bool _gotDefaultProperty;
638 AttributeCollection _attributes;
640 public Info (Type infoType)
642 _infoType = infoType;
645 public abstract AttributeCollection GetAttributes ();
646 public abstract EventDescriptorCollection GetEvents ();
647 public abstract PropertyDescriptorCollection GetProperties ();
651 get { return _infoType; }
654 public EventDescriptorCollection GetEvents (Attribute[] attributes)
656 EventDescriptorCollection evs = GetEvents ();
657 if (attributes == null)
660 return evs.Filter (attributes);
663 public PropertyDescriptorCollection GetProperties (Attribute[] attributes)
665 PropertyDescriptorCollection props = GetProperties ();
666 if (attributes == null)
669 return props.Filter (attributes);
672 public EventDescriptor GetDefaultEvent ()
674 if (_gotDefaultEvent)
675 return _defaultEvent;
677 DefaultEventAttribute attr = (DefaultEventAttribute) GetAttributes()[typeof(DefaultEventAttribute)];
678 if (attr == null || attr.Name == null)
679 _defaultEvent = null;
681 EventDescriptorCollection events = GetEvents ();
682 _defaultEvent = events [attr.Name];
684 // In our test case (TypeDescriptorTest.TestGetDefaultEvent), we have
685 // a scenario where a custom filter adds the DefaultEventAttribute,
686 // but its FilterEvents method removes the event the
687 // DefaultEventAttribute applied to. .NET 1.x accepts this and returns
688 // the *other* event defined in the class.
690 // Consequently, we know we have a DefaultEvent, but we need to check
691 // and ensure that the requested event is unfiltered. If it is, just
692 // grab the first element in the collection.
693 if (_defaultEvent == null && events.Count > 0)
694 _defaultEvent = events [0];
697 _gotDefaultEvent = true;
698 return _defaultEvent;
701 public PropertyDescriptor GetDefaultProperty ()
703 if (_gotDefaultProperty)
704 return _defaultProperty;
706 DefaultPropertyAttribute attr = (DefaultPropertyAttribute) GetAttributes()[typeof(DefaultPropertyAttribute)];
707 if (attr == null || attr.Name == null)
708 _defaultProperty = null;
710 PropertyDescriptorCollection properties = GetProperties ();
711 _defaultProperty = properties[attr.Name];
713 _gotDefaultProperty = true;
714 return _defaultProperty;
717 protected AttributeCollection GetAttributes (IComponent comp)
719 if (_attributes != null)
723 object[] ats = _infoType.GetCustomAttributes (true);
724 Hashtable t = new Hashtable ();
726 // Filter the custom attributes, so that only the top
727 // level of the same type are left.
729 for (int i = ats.Length -1; i >= 0; i--) {
730 t [((Attribute) ats[i]).TypeId] = ats[i];
733 if (comp != null && comp.Site != null)
735 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) comp.Site.GetService (typeof(ITypeDescriptorFilterService));
736 cache = filter.FilterAttributes (comp, t);
739 ArrayList atts = new ArrayList ();
740 atts.AddRange (t.Values);
741 AttributeCollection attCol = new AttributeCollection (atts);
743 _attributes = attCol;
748 internal class ComponentInfo : Info
750 IComponent _component;
751 EventDescriptorCollection _events;
752 PropertyDescriptorCollection _properties;
754 public ComponentInfo (IComponent component): base (component.GetType())
756 _component = component;
759 public override AttributeCollection GetAttributes ()
761 return base.GetAttributes (_component);
764 public override EventDescriptorCollection GetEvents ()
770 EventInfo[] events = _component.GetType().GetEvents ();
771 Hashtable t = new Hashtable ();
772 foreach (EventInfo ev in events)
773 t [ev.Name] = new ReflectionEventDescriptor (ev);
775 if (_component.Site != null)
777 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) _component.Site.GetService (typeof(ITypeDescriptorFilterService));
778 cache = filter.FilterEvents (_component, t);
781 ArrayList atts = new ArrayList ();
782 atts.AddRange (t.Values);
783 EventDescriptorCollection attCol = new EventDescriptorCollection (atts);
784 if (cache) _events = attCol;
788 public override PropertyDescriptorCollection GetProperties ()
790 if (_properties != null)
794 PropertyInfo[] props = _component.GetType().GetProperties (BindingFlags.Instance | BindingFlags.Public);
795 Hashtable t = new Hashtable ();
796 foreach (PropertyInfo pr in props)
797 t [pr.Name] = new ReflectionPropertyDescriptor (pr);
799 if (_component.Site != null)
801 ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) _component.Site.GetService (typeof(ITypeDescriptorFilterService));
802 cache = filter.FilterProperties (_component, t);
805 PropertyDescriptor[] descriptors = new PropertyDescriptor[t.Values.Count];
806 t.Values.CopyTo (descriptors, 0);
807 PropertyDescriptorCollection attCol = new PropertyDescriptorCollection (descriptors, true);
809 _properties = attCol;
814 internal class TypeInfo : Info
816 EventDescriptorCollection _events;
817 PropertyDescriptorCollection _properties;
819 public TypeInfo (Type t): base (t)
823 public override AttributeCollection GetAttributes ()
825 return base.GetAttributes (null);
828 public override EventDescriptorCollection GetEvents ()
833 EventInfo[] events = InfoType.GetEvents ();
834 EventDescriptor[] descs = new EventDescriptor [events.Length];
835 for (int n=0; n<events.Length; n++)
836 descs [n] = new ReflectionEventDescriptor (events[n]);
838 _events = new EventDescriptorCollection (descs);
842 public override PropertyDescriptorCollection GetProperties ()
844 if (_properties != null)
847 PropertyInfo[] props = InfoType.GetProperties (BindingFlags.Instance | BindingFlags.Public);
848 ArrayList descs = new ArrayList (props.Length);
849 for (int n=0; n<props.Length; n++)
850 if (props [n].GetIndexParameters ().Length == 0)
851 descs.Add (new ReflectionPropertyDescriptor (props[n]));
853 _properties = new PropertyDescriptorCollection ((PropertyDescriptor[]) descs.ToArray (typeof (PropertyDescriptor)), true);