Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / CompMod / System / ComponentModel / ReflectTypeDescriptionProvider.cs / 6 / ReflectTypeDescriptionProvider.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.ComponentModel { using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel.Design; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Security; using System.Security.Permissions; ////// This type description provider provides type information through /// reflection. Unless someone has provided a custom type description /// provider for a type or instance, or unless an instance implements /// ICustomTypeDescriptor, any query for type information will go through /// this class. There should be a single instance of this class associated /// with "object", as it can provide all type information for any type. /// [HostProtection(SharedState = true)] internal sealed class ReflectTypeDescriptionProvider : TypeDescriptionProvider { // Hastable of Type -> ReflectedTypeData. ReflectedTypeData contains all // of the type information we have gathered for a given type. // private Hashtable _typeData; // This is the signature we look for when creating types that are generic, but // want to know what type they are dealing with. Enums are a good example of this; // there is one enum converter that can work with all enums, but it needs to know // the type of enum it is dealing with. // private static Type[] _typeConstructor = new Type[] {typeof(Type)}; // This is where we store the various converters, etc for the intrinsic types. // private static Hashtable _editorTables; private static Hashtable _intrinsicTypeConverters; // For converters, etc that are bound to class attribute data, rather than a class // type, we have special key sentinel values that we put into the hash table. // private static object _intrinsicReferenceKey = new object(); private static object _intrinsicNullableKey = new object(); // The key we put into IDictionaryService to store our cache dictionary. // private static object _dictionaryKey = new object(); // This is a cache on top of core reflection. The cache // builds itself recursively, so if you ask for the properties // on Control, Component and object are also automatically filled // in. The keys to the property and event caches are types. // The keys to the attribute cache are either MemberInfos or types. // private static Hashtable _propertyCache; private static Hashtable _eventCache; private static Hashtable _attributeCache; private static Hashtable _extendedPropertyCache; // These are keys we stuff into our object cache. We use this // cache data to store extender provider info for an object. // private static readonly Guid _extenderProviderKey = Guid.NewGuid(); private static readonly Guid _extenderPropertiesKey = Guid.NewGuid(); private static readonly Guid _extenderProviderPropertiesKey = Guid.NewGuid(); // These are attribute that, when we discover them on interfaces, we do // not merge them into the attribute set for a class. private static readonly Type[] _skipInterfaceAttributeList = new Type[] { typeof(System.Runtime.InteropServices.GuidAttribute), typeof(System.Runtime.InteropServices.ComVisibleAttribute), typeof(System.Runtime.InteropServices.InterfaceTypeAttribute) }; internal static Guid ExtenderProviderKey { get { return _extenderProviderKey; } } private static object _internalSyncObject = new object(); ////// Creates a new ReflectTypeDescriptionProvider. The type is the /// type we will obtain type information for. /// internal ReflectTypeDescriptionProvider() { TypeDescriptor.Trace("Reflect : Creating ReflectTypeDescriptionProvider"); } ////// This is a table we create for intrinsic types. /// There should be entries here ONLY for intrinsic /// types, as all other types we should be able to /// add attributes directly as metadata. /// private static Hashtable IntrinsicTypeConverters { get { // It is not worth taking a lock for this -- worst case of a collision // would build two tables, one that garbage collects very quickly. // if (_intrinsicTypeConverters == null) { Hashtable temp = new Hashtable(); // Add the intrinsics // temp[typeof(bool)] = typeof(BooleanConverter); temp[typeof(byte)] = typeof(ByteConverter); temp[typeof(SByte)] = typeof(SByteConverter); temp[typeof(char)] = typeof(CharConverter); temp[typeof(double)] = typeof(DoubleConverter); temp[typeof(string)] = typeof(StringConverter); temp[typeof(int)] = typeof(Int32Converter); temp[typeof(short)] = typeof(Int16Converter); temp[typeof(long)] = typeof(Int64Converter); temp[typeof(float)] = typeof(SingleConverter); temp[typeof(UInt16)] = typeof(UInt16Converter); temp[typeof(UInt32)] = typeof(UInt32Converter); temp[typeof(UInt64)] = typeof(UInt64Converter); temp[typeof(object)] = typeof(TypeConverter); temp[typeof(void)] = typeof(TypeConverter); temp[typeof(CultureInfo)] = typeof(CultureInfoConverter); temp[typeof(DateTime)] = typeof(DateTimeConverter); temp[typeof(DateTimeOffset)] = typeof(DateTimeOffsetConverter); temp[typeof(Decimal)] = typeof(DecimalConverter); temp[typeof(TimeSpan)] = typeof(TimeSpanConverter); temp[typeof(Guid)] = typeof(GuidConverter); temp[typeof(Array)] = typeof(ArrayConverter); temp[typeof(ICollection)] = typeof(CollectionConverter); temp[typeof(Enum)] = typeof(EnumConverter); // Special cases for things that are not bound to a specific type // temp[_intrinsicReferenceKey] = typeof(ReferenceConverter); temp[_intrinsicNullableKey] = typeof(NullableConverter); _intrinsicTypeConverters = temp; } return _intrinsicTypeConverters; } } ////// Adds an editor table for the given editor base type. /// ypically, editors are specified as metadata on an object. If no metadata for a /// equested editor base type can be found on an object, however, the /// ypeDescriptor will search an editor /// able for the editor type, if one can be found. /// internal static void AddEditorTable(Type editorBaseType, Hashtable table) { if (editorBaseType == null) { throw new ArgumentNullException("editorBaseType"); } if (table == null) { Debug.Fail("COMPAT: Editor table should not be null"); // don't throw; RTM didn't so we can't do it either. } lock(_internalSyncObject) { if (_editorTables == null) { _editorTables = new Hashtable(4); } if (!_editorTables.ContainsKey(editorBaseType)) { _editorTables[editorBaseType] = table; } } } ////// CreateInstance implementation. We delegate to Activator. /// public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) { Debug.Assert(objectType != null, "Should have arg-checked before coming in here"); object obj = null; if (argTypes != null) { obj = SecurityUtils.SecureConstructorInvoke(objectType, argTypes, args, true, BindingFlags.ExactBinding); } else { if (args != null) { argTypes = new Type[args.Length]; for(int idx = 0; idx < args.Length; idx++) { if (args[idx] != null) { argTypes[idx] = args[idx].GetType(); } else { argTypes[idx] = typeof(object); } } } else { argTypes = new Type[0]; } obj = SecurityUtils.SecureConstructorInvoke(objectType, argTypes, args, true); } if (obj == null) { obj = SecurityUtils.SecureCreateInstance(objectType, args); } return obj; } ////// Helper method to create editors and type converters. This checks to see if the /// type implements a Type constructor, and if it does it invokes that ctor. /// Otherwise, it just tries to create the type. /// private static object CreateInstance(Type objectType, Type callingType) { object obj = SecurityUtils.SecureConstructorInvoke(objectType, _typeConstructor, new object[] {callingType}, false); if (obj == null) { obj = SecurityUtils.SecureCreateInstance(objectType); } return obj; } ////// Retrieves custom attributes. /// internal AttributeCollection GetAttributes(Type type) { ReflectedTypeData td = GetTypeData(type, true); return td.GetAttributes(); } ////// Our implementation of GetCache sits on top of IDictionaryService. /// public override IDictionary GetCache(object instance) { IComponent comp = instance as IComponent; if (comp != null && comp.Site != null) { IDictionaryService ds = comp.Site.GetService(typeof(IDictionaryService)) as IDictionaryService; if (ds != null) { IDictionary dict = ds.GetValue(_dictionaryKey) as IDictionary; if (dict == null) { dict = new Hashtable(); ds.SetValue(_dictionaryKey, dict); } return dict; } } return null; } ////// Retrieves the class name for our type. /// internal string GetClassName(Type type) { ReflectedTypeData td = GetTypeData(type, true); return td.GetClassName(null); } ////// Retrieves the component name from the site. /// internal string GetComponentName(Type type, object instance) { ReflectedTypeData td = GetTypeData(type, true); return td.GetComponentName(instance); } ////// Retrieves the type converter. If instance is non-null, /// it will be used to retrieve attributes. Otherwise, _type /// will be used. /// internal TypeConverter GetConverter(Type type, object instance) { ReflectedTypeData td = GetTypeData(type, true); return td.GetConverter(instance); } ////// Return the default event. The default event is determined by the /// presence of a DefaultEventAttribute on the class. /// internal EventDescriptor GetDefaultEvent(Type type, object instance) { ReflectedTypeData td = GetTypeData(type, true); return td.GetDefaultEvent(instance); } ////// Return the default property. /// internal PropertyDescriptor GetDefaultProperty(Type type, object instance) { ReflectedTypeData td = GetTypeData(type, true); return td.GetDefaultProperty(instance); } ////// Retrieves the editor for the given base type. /// internal object GetEditor(Type type, object instance, Type editorBaseType) { ReflectedTypeData td = GetTypeData(type, true); return td.GetEditor(instance, editorBaseType); } ////// Retrieves a default editor table for the given editor base type. /// private static Hashtable GetEditorTable(Type editorBaseType) { if (_editorTables == null) { lock(_internalSyncObject) { if (_editorTables == null) { _editorTables = new Hashtable(4); } } } object table = _editorTables[editorBaseType]; if (table == null) { // Before we give up, it is possible that the // class initializer for editorBaseType hasn't // actually run. // System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(editorBaseType.TypeHandle); table = _editorTables[editorBaseType]; // If the table is still null, then throw a // sentinel in there so we don't // go through this again. // if (table == null) { lock (_internalSyncObject) { table = _editorTables[editorBaseType]; if (table == null) { _editorTables[editorBaseType] = _editorTables; } } } } // Look for our sentinel value that indicates // we have already tried and failed to get // a table. // if (table == _editorTables) { table = null; } return (Hashtable)table; } ////// Retrieves the events for this type. /// internal EventDescriptorCollection GetEvents(Type type) { ReflectedTypeData td = GetTypeData(type, true); return td.GetEvents(); } ////// Retrieves custom extender attributes. We don't support /// extender attributes, so we always return an empty collection. /// internal AttributeCollection GetExtendedAttributes(object instance) { return AttributeCollection.Empty; } ////// Retrieves the class name for our type. /// internal string GetExtendedClassName(object instance) { return GetClassName(instance.GetType()); } ////// Retrieves the component name from the site. /// internal string GetExtendedComponentName(object instance) { return GetComponentName(instance.GetType(), instance); } ////// Retrieves the type converter. If instance is non-null, /// it will be used to retrieve attributes. Otherwise, _type /// will be used. /// internal TypeConverter GetExtendedConverter(object instance) { return GetConverter(instance.GetType(), instance); } ////// Return the default event. The default event is determined by the /// presence of a DefaultEventAttribute on the class. /// internal EventDescriptor GetExtendedDefaultEvent(object instance) { return null; // we don't support extended events. } ////// Return the default property. /// internal PropertyDescriptor GetExtendedDefaultProperty(object instance) { return null; // extender properties are never the default. } ////// Retrieves the editor for the given base type. /// internal object GetExtendedEditor(object instance, Type editorBaseType) { return GetEditor(instance.GetType(), instance, editorBaseType); } ////// Retrieves the events for this type. /// internal EventDescriptorCollection GetExtendedEvents(object instance) { return EventDescriptorCollection.Empty; } ////// Retrieves the properties for this type. /// internal PropertyDescriptorCollection GetExtendedProperties(object instance) { // Is this object a sited component? If not, then it // doesn't have any extender properties. // Type componentType = instance.GetType(); IComponent component = instance as IComponent; if (component == null || component.Site == null) { return PropertyDescriptorCollection.Empty; } // Check the component for extender providers. We prefer // IExtenderListService, but will use the container if that's // all we have. In either case, we check the list of extenders // against previously stored data in the object cache. If // the cache is up to date, we just return the extenders in the // cache. // IExtenderProvider[] extenders = null; IExtenderListService extenderList = component.Site.GetService(typeof(IExtenderListService)) as IExtenderListService; IDictionary cache = TypeDescriptor.GetCache(instance); if (extenderList != null) { extenders = GetExtenders(extenderList.GetExtenderProviders(), instance, cache); } else { IContainer cont = component.Site.Container; if (cont != null) { extenders = GetExtenders (cont.Components, instance, cache); } } if (extenders == null) { return PropertyDescriptorCollection.Empty; } // Ok, we have a set of extenders. Now, check to see if there // are properties already in our object cache. If there aren't, // then we will need to create them. // PropertyDescriptorCollection properties = null; if (cache != null) { properties = cache[_extenderPropertiesKey] as PropertyDescriptorCollection; } if (properties != null) { return properties; } // Unlike normal properties, it is fine for there to be properties with // duplicate names here. // ArrayList propertyList = null; for (int idx = 0; idx < extenders.Length; idx++) { PropertyDescriptor[] propertyArray = ReflectGetExtendedProperties(extenders[idx]); if (propertyList == null) { propertyList = new ArrayList(propertyArray.Length * extenders.Length); } for (int propIdx = 0; propIdx < propertyArray.Length; propIdx++) { PropertyDescriptor prop = propertyArray[propIdx]; ExtenderProvidedPropertyAttribute eppa = prop.Attributes[typeof(ExtenderProvidedPropertyAttribute)] as ExtenderProvidedPropertyAttribute; Debug.Assert(eppa != null, "Extender property " + prop.Name + " has no provider attribute. We will skip it."); if (eppa != null) { Type receiverType = eppa.ReceiverType; if (receiverType != null) { if (receiverType.IsAssignableFrom(componentType)) { propertyList.Add(prop); } } } } } // propertyHash now contains ExtendedPropertyDescriptor objects // for each extended property. // if (propertyList != null) { TypeDescriptor.Trace("Extenders : Allocating property collection for {0} properties", propertyList.Count); PropertyDescriptor[] fullArray = new PropertyDescriptor[propertyList.Count]; propertyList.CopyTo(fullArray, 0); properties = new PropertyDescriptorCollection(fullArray, true); } else { properties = PropertyDescriptorCollection.Empty; } if (cache != null) { TypeDescriptor.Trace("Extenders : caching extender results"); cache[_extenderPropertiesKey] = properties; } return properties; } ////// GetExtenders builds a list of extender providers from /// a collection of components. It validates the extenders /// against any cached collection of extenders in the /// cache. If there is a discrepancy, this will erase /// any cached extender properties from the cache and /// save the updated extender list. If there is no /// discrepancy this will simply return the cached list. /// private static IExtenderProvider[] GetExtenders(ICollection components, object instance, IDictionary cache) { bool newExtenders = false; int extenderCount = 0; IExtenderProvider[] existingExtenders = null; //CanExtend is expensive. We will remember results of CanExtend for the first 64 extenders and using "long canExtend" as a bit vector. // we want to avoid memory allocation as well so we don't use some more sophisticated data structure like an array of booleans UInt64 canExtend = 0; int maxCanExtendResults = 64; // currentExtenders is what we intend to return. If the caller passed us // the return value from IExtenderListService, components will already be // an IExtenderProvider[]. If not, then we must treat components as an // opaque collection. We spend a great deal of energy here to avoid // copying or allocating memory because this method is called every // time a component is asked for its properties. IExtenderProvider[] currentExtenders = components as IExtenderProvider[]; if (cache != null) { existingExtenders = cache[_extenderProviderKey] as IExtenderProvider[]; } if (existingExtenders == null) { newExtenders = true; } int curIdx = 0; int idx = 0; if (currentExtenders != null) { for (curIdx = 0; curIdx < currentExtenders.Length; curIdx++) { if (currentExtenders[curIdx].CanExtend(instance)) { extenderCount++; // Performance:We would like to call CanExtend as little as possible therefore we remember its result if (curIdx < maxCanExtendResults) canExtend |= (UInt64)1 << curIdx; if (!newExtenders && (idx >= existingExtenders.Length || currentExtenders[curIdx] != existingExtenders[idx++])) { newExtenders = true; } } } } else if (components != null) { foreach(object obj in components) { IExtenderProvider prov = obj as IExtenderProvider; if (prov != null && prov.CanExtend(instance)) { extenderCount++; if (curIdx < maxCanExtendResults) canExtend |= (UInt64)1<= existingExtenders.Length || prov != existingExtenders[idx++])) { newExtenders = true; } } curIdx++; } } if (existingExtenders != null && extenderCount != existingExtenders.Length) { newExtenders = true; } if (newExtenders) { TypeDescriptor.Trace("Extenders : object has new extenders : {0}", instance.GetType().Name); TypeDescriptor.Trace("Extenders : Identified {0} extender providers", extenderCount); if (currentExtenders == null || extenderCount != currentExtenders.Length) { IExtenderProvider[] newExtenderArray = new IExtenderProvider[extenderCount]; curIdx = 0; idx = 0; if (currentExtenders != null && extenderCount > 0) { while(curIdx < currentExtenders.Length) { if ((curIdx < maxCanExtendResults && (canExtend & ((UInt64)1 << curIdx)) != 0 )|| (curIdx >= maxCanExtendResults && currentExtenders[curIdx].CanExtend(instance))) { Debug.Assert(idx < extenderCount, "There are more extenders than we expect"); newExtenderArray[idx++] = currentExtenders[curIdx]; } curIdx++; } Debug.Assert(idx == extenderCount, "Wrong number of extenders"); } else if (extenderCount > 0) { IEnumerator componentEnum = components.GetEnumerator(); while(componentEnum.MoveNext()) { IExtenderProvider p = componentEnum.Current as IExtenderProvider; if (p != null && ((curIdx < maxCanExtendResults && (canExtend & ((UInt64)1 << curIdx)) != 0) || (curIdx >= maxCanExtendResults && p.CanExtend(instance)))) { Debug.Assert(idx < extenderCount, "There are more extenders than we expect"); newExtenderArray[idx++] = p; } curIdx++; } Debug.Assert(idx == extenderCount, "Wrong number of extenders"); } currentExtenders = newExtenderArray; } if (cache != null) { TypeDescriptor.Trace("Extenders : caching extender provider results"); cache[_extenderProviderKey] = currentExtenders; cache.Remove(_extenderPropertiesKey); } } else { currentExtenders = existingExtenders; } return currentExtenders; } /// /// Retrieves the owner for a property. /// internal object GetExtendedPropertyOwner(object instance, PropertyDescriptor pd) { return GetPropertyOwner(instance.GetType(), instance, pd); } ////////////////////////////////////////////////////////// ////// Provides a type descriptor for the given object. We only support this /// if the object is a component that /// public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance) { Debug.Fail("This should never be invoked. TypeDescriptionNode should wrap for us."); return null; } ////// The name of the specified component, or null if the component has no name. /// In many cases this will return the same value as GetComponentName. If the /// component resides in a nested container or has other nested semantics, it may /// return a different fully qualfied name. /// /// If not overridden, the default implementation of this method will call /// GetComponentName. /// public override string GetFullComponentName(object component) { IComponent comp = component as IComponent; if (comp != null) { INestedSite ns = comp.Site as INestedSite; if (ns != null) { return ns.FullName; } } return TypeDescriptor.GetComponentName(component); } ////// Returns an array of types we have populated metadata for that live /// in the current module. /// internal Type[] GetPopulatedTypes(Module module) { ArrayList typeList = new ArrayList();; foreach(DictionaryEntry de in _typeData) { Type type = (Type)de.Key; ReflectedTypeData typeData = (ReflectedTypeData)de.Value; if (type.Module == module && typeData.IsPopulated) { typeList.Add(type); } } return (Type[])typeList.ToArray(typeof(Type)); } ////// Retrieves the properties for this type. /// internal PropertyDescriptorCollection GetProperties(Type type) { ReflectedTypeData td = GetTypeData(type, true); return td.GetProperties(); } ////// Retrieves the owner for a property. /// internal object GetPropertyOwner(Type type, object instance, PropertyDescriptor pd) { return TypeDescriptor.GetAssociation(type, instance); } ////// Returns an Type for the given type. Since type implements IReflect, /// we just return objectType. /// public override Type GetReflectionType(Type objectType, object instance) { Debug.Assert(objectType != null, "Should have arg-checked before coming in here"); return objectType; } ////// Returns the type data for the given type, or /// null if there is no type data for the type yet and /// createIfNeeded is false. /// private ReflectedTypeData GetTypeData(Type type, bool createIfNeeded) { ReflectedTypeData td = null; if (_typeData != null) { td = (ReflectedTypeData)_typeData[type]; if (td != null) { return td; } } lock (_internalSyncObject) { if (_typeData != null) { td = (ReflectedTypeData)_typeData[type]; } if (td == null && createIfNeeded) { td = new ReflectedTypeData(type); if (_typeData == null) { _typeData = new Hashtable(); } _typeData[type] = td; } } return td; } ////// This method returns a custom type descriptor for the given type / object. /// The objectType parameter is always valid, but the instance parameter may /// be null if no instance was passed to TypeDescriptor. The method should /// return a custom type descriptor for the object. If the method is not /// interested in providing type information for the object it should /// return null. /// public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { Debug.Fail("This should never be invoked. TypeDescriptionNode should wrap for us."); return null; } ////// Retrieves a type from a name. /// private static Type GetTypeFromName(string typeName) { Type t = Type.GetType(typeName); if (t == null) { int commaIndex = typeName.IndexOf(','); if (commaIndex != -1) { // At design time, it's possible for us to reuse // an assembly but add new types. The app domain // will cache the assembly based on identity, however, // so it could be looking in the previous version // of the assembly and not finding the type. We work // around this by looking for the non-assembly qualified // name, which causes the domain to raise a type // resolve event. // t = Type.GetType(typeName.Substring(0, commaIndex)); } } return t; } ////// This method returns true if the data cache in this reflection /// type descriptor has data in it. /// internal bool IsPopulated(Type type) { ReflectedTypeData td = GetTypeData(type, false); if (td != null) { return td.IsPopulated; } return false; } ////// Static helper API around reflection to get and cache /// custom attributes. This does not recurse, but it will /// walk interfaces on the type. Interfaces are added /// to the end, so merging should be done from length - 1 /// to 0. /// private static Attribute[] ReflectGetAttributes(Type type) { if (_attributeCache == null) { lock (_internalSyncObject) { if (_attributeCache == null) { _attributeCache = new Hashtable(); } } } Attribute[] attrs = (Attribute[])_attributeCache[type]; if (attrs == null) { TypeDescriptor.Trace("Attributes : Building attributes for {0}", type.Name); // Get the type's attributes. // object[] typeAttrs = type.GetCustomAttributes(typeof(Attribute), false); attrs = new Attribute[typeAttrs.Length]; typeAttrs.CopyTo(attrs, 0); _attributeCache[type] = attrs; } return attrs; } ////// Static helper API around reflection to get and cache /// custom attributes. This does not recurse to the base class. /// internal static Attribute[] ReflectGetAttributes(MemberInfo member) { if (_attributeCache == null) { lock (_internalSyncObject) { if (_attributeCache == null) { _attributeCache = new Hashtable(); } } } Attribute[] attrs = (Attribute[])_attributeCache[member]; if (attrs == null) { // Get the member's attributes. // object[] memberAttrs = member.GetCustomAttributes(typeof(Attribute), false); attrs = new Attribute[memberAttrs.Length]; memberAttrs.CopyTo(attrs, 0); _attributeCache[member] = attrs; } return attrs; } ////// Static helper API around reflection to get and cache /// events. This does not recurse to the base class. /// private static EventDescriptor[] ReflectGetEvents(Type type) { if (_eventCache == null) { lock (_internalSyncObject) { if (_eventCache == null) { _eventCache = new Hashtable(); } } } EventDescriptor[] events = (EventDescriptor[])_eventCache[type]; if (events == null) { BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance; TypeDescriptor.Trace("Events : Building events for {0}", type.Name); // Get the type's events. Events may have their add and // remove methods individually overridden in a derived // class, but at some point in the base class chain both // methods must exist. If we find an event that doesn't // have both add and remove, we skip it here, because it // will be picked up in our base class scan. // EventInfo[] eventInfos = type.GetEvents(bindingFlags); events = new EventDescriptor[eventInfos.Length]; int eventCount = 0; for (int idx = 0; idx < eventInfos.Length; idx++) { EventInfo eventInfo = eventInfos[idx]; // GetEvents returns events that are on nonpublic types // if those types are from our assembly. Screen these. // if ((!(eventInfo.DeclaringType.IsPublic || eventInfo.DeclaringType.IsNestedPublic)) && (eventInfo.DeclaringType.Assembly == typeof(ReflectTypeDescriptionProvider).Assembly)) { Debug.Fail("Hey, assumption holds true. Rip this assert."); continue; } MethodInfo addMethod = eventInfo.GetAddMethod(); MethodInfo removeMethod = eventInfo.GetRemoveMethod(); if (addMethod != null && removeMethod != null) { events[eventCount++] = new ReflectEventDescriptor(type, eventInfo); } } if (eventCount != events.Length) { EventDescriptor[] newEvents = new EventDescriptor[eventCount]; Array.Copy(events, 0, newEvents, 0, eventCount); events = newEvents; } #if DEBUG foreach(EventDescriptor dbgEvent in events) { Debug.Assert(dbgEvent != null, "Holes in event array for type " + type); } #endif _eventCache[type] = events; } return events; } ////// This performs the actual reflection needed to discover /// extender properties. If object caching is supported this /// will maintain a cache of property descriptors on the /// extender provider. Extender properties are actually two /// property descriptors in one. There is a chunk of per-class /// data in a ReflectPropertyDescriptor that defines the /// parameter types and get and set methods of the extended property, /// and there is an ExtendedPropertyDescriptor that combines this /// with an extender provider object to create what looks like a /// normal property. ReflectGetExtendedProperties maintains two /// separate caches for these two sets: a static one for the /// ReflectPropertyDescriptor values that don't change for each /// provider instance, and a per-provider cache that contains /// the ExtendedPropertyDescriptors. /// private static PropertyDescriptor[] ReflectGetExtendedProperties(IExtenderProvider provider) { IDictionary cache = TypeDescriptor.GetCache(provider); PropertyDescriptor[] properties; if (cache != null) { properties = cache[_extenderProviderPropertiesKey] as PropertyDescriptor[]; if (properties != null) { return properties; } } // Our per-instance cache missed. We have never seen this instance of the // extender provider before. See if we can find our class-based // property store. // if (_extendedPropertyCache == null) { lock (_internalSyncObject) { if (_extendedPropertyCache == null) { _extendedPropertyCache = new Hashtable(); } } } Type providerType = provider.GetType(); ReflectPropertyDescriptor[] extendedProperties = (ReflectPropertyDescriptor[])_extendedPropertyCache[providerType]; // Our class-based property store failed as well, so we need to build up the set of // extended properties here. // if (extendedProperties == null) { AttributeCollection attributes = TypeDescriptor.GetAttributes(providerType); ArrayList extendedList = new ArrayList(attributes.Count); foreach(Attribute attr in attributes) { ProvidePropertyAttribute provideAttr = attr as ProvidePropertyAttribute; if (provideAttr != null) { Type receiverType = GetTypeFromName(provideAttr.ReceiverTypeName); if (receiverType != null) { MethodInfo getMethod = providerType.GetMethod("Get" + provideAttr.PropertyName, new Type[] {receiverType}); if (getMethod != null && !getMethod.IsStatic && getMethod.IsPublic) { MethodInfo setMethod = providerType.GetMethod("Set" + provideAttr.PropertyName, new Type[] {receiverType, getMethod.ReturnType}); if (setMethod != null && (setMethod.IsStatic || !setMethod.IsPublic)) { setMethod = null; } extendedList.Add(new ReflectPropertyDescriptor(providerType, provideAttr.PropertyName, getMethod.ReturnType, receiverType, getMethod, setMethod, null)); } } } } extendedProperties = new ReflectPropertyDescriptor[extendedList.Count]; extendedList.CopyTo(extendedProperties, 0); _extendedPropertyCache[providerType] = extendedProperties; } // Now that we have our extended properties we can build up a list of callable properties. These can be // returned to the user. // properties = new PropertyDescriptor[extendedProperties.Length]; for (int idx = 0; idx < extendedProperties.Length; idx++) { Attribute[] attrs = null; IComponent comp = provider as IComponent; if (comp == null || comp.Site == null) { attrs = new Attribute[] {DesignOnlyAttribute.Yes}; } ReflectPropertyDescriptor rpd = extendedProperties[idx]; ExtendedPropertyDescriptor epd = new ExtendedPropertyDescriptor(rpd, rpd.ExtenderGetReceiverType(), provider, attrs); properties[idx] = epd; } if (cache != null) { cache[_extenderProviderPropertiesKey] = properties; } return properties; } ////// Static helper API around reflection to get and cache /// properties. This does not recurse to the base class. /// private static PropertyDescriptor[] ReflectGetProperties(Type type) { if (_propertyCache == null) { lock(_internalSyncObject) { if (_propertyCache == null) { _propertyCache = new Hashtable(); } } } PropertyDescriptor[] properties = (PropertyDescriptor[])_propertyCache[type]; if (properties == null) { BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance; TypeDescriptor.Trace("Properties : Building properties for {0}", type.Name); // Get the type's properties. Properties may have their // get and set methods individually overridden in a derived // class, so if we find a missing method we need to walk // down the base class chain to find it. We actually merge // "new" properties of the same name, so we must preserve // the member info for each method individually. // PropertyInfo[] propertyInfos = type.GetProperties(bindingFlags); properties = new PropertyDescriptor[propertyInfos.Length]; int propertyCount = 0; for (int idx = 0; idx < propertyInfos.Length; idx++) { PropertyInfo propertyInfo = propertyInfos[idx]; // Today we do not support parameterized properties. // if (propertyInfo.GetIndexParameters().Length > 0) { continue; } MethodInfo getMethod = propertyInfo.GetGetMethod(); MethodInfo setMethod = propertyInfo.GetSetMethod(); string name = propertyInfo.Name; // If the property only overrode "set", then we don't // pick it up here. Rather, we just merge it in from // the base class list. // If a property had at least a get method, we consider it. We don't // consider write-only properties. // if (getMethod != null) { properties[propertyCount++] = new ReflectPropertyDescriptor(type, name, propertyInfo.PropertyType, propertyInfo, getMethod, setMethod, null); } } if (propertyCount != properties.Length) { PropertyDescriptor[] newProperties = new PropertyDescriptor[propertyCount]; Array.Copy(properties, 0, newProperties, 0, propertyCount); properties = newProperties; } #if DEBUG foreach(PropertyDescriptor dbgProp in properties) { Debug.Assert(dbgProp != null, "Holes in property array for type " + type); } #endif _propertyCache[type] = properties; } return properties; } ////// Refreshes the contents of this type descriptor. This does not /// actually requery, but it will clear our state so the next /// query re-populates. /// internal void Refresh(Type type) { ReflectedTypeData td = GetTypeData(type, false); if (td != null) { td.Refresh(); } } ////// Searches the provided intrinsic hashtable for a match with the object type. /// At the beginning, the hashtable contains types for the various converters. /// As this table is searched, the types for these objects /// are replaced with instances, so we only create as needed. This method /// does the search up the base class hierarchy and will create instances /// for types as needed. These instances are stored back into the table /// for the base type, and for the original component type, for fast access. /// private static object SearchIntrinsicTable(Hashtable table, Type callingType) { object hashEntry = null; // We take a lock on this table. Nothing in this code calls out to // other methods that lock, so it should be fairly safe to grab this // lock. Also, this allows multiple intrinsic tables to be searched // at once. // lock(table) { Type baseType = callingType; while (baseType != null && baseType != typeof(object)) { hashEntry = table[baseType]; // If the entry is a late-bound type, then try to // resolve it. // string typeString = hashEntry as string; if (typeString != null) { hashEntry = Type.GetType(typeString); if (hashEntry != null) { table[baseType] = hashEntry; } } if (hashEntry != null) { break; } baseType = baseType.BaseType; } // Now make a scan through each value in the table, looking for interfaces. // If we find one, see if the object implements the interface. // if (hashEntry == null) { foreach(DictionaryEntry de in table) { Type keyType = de.Key as Type; if (keyType != null && keyType.IsInterface && keyType.IsAssignableFrom(callingType)) { hashEntry = de.Value; string typeString = hashEntry as string; if (typeString != null) { hashEntry = Type.GetType(typeString); if (hashEntry != null) { table[callingType] = hashEntry; } } if (hashEntry != null) { break; } } } } // Special case converters // if (hashEntry == null) { if (callingType.IsGenericType && callingType.GetGenericTypeDefinition() == typeof(Nullable<>)) { // Check if it is a nullable value hashEntry = table[_intrinsicNullableKey]; } else if (callingType.IsInterface) { // Finally, check to see if the component type is some unknown interface. // We have a custom converter for that. hashEntry = table[_intrinsicReferenceKey]; } } // Interfaces do not derive from object, so we // must handle the case of no hash entry here. // if (hashEntry == null) { hashEntry = table[typeof(object)]; } // If the entry is a type, create an instance of it and then // replace the entry. This way we only need to create once. // We can only do this if the object doesn't want a type // in its constructor. // Type type = hashEntry as Type; if (type != null) { hashEntry = CreateInstance(type, callingType); if (type.GetConstructor(_typeConstructor) == null) { table[callingType] = hashEntry; } } } return hashEntry; } ////// This class contains all the reflection information for a /// given type. /// private class ReflectedTypeData { private Type _type; private AttributeCollection _attributes; private EventDescriptorCollection _events; private PropertyDescriptorCollection _properties; private TypeConverter _converter; private object[] _editors; private Type[] _editorTypes; private int _editorCount; internal ReflectedTypeData(Type type) { _type = type; TypeDescriptor.Trace("Reflect : Creating ReflectedTypeData for {0}", type.Name); } ////// This method returns true if the data cache in this reflection /// type descriptor has data in it. /// internal bool IsPopulated { get { return (_attributes != null) | (_events != null) | (_properties != null); } } ////// Retrieves custom attributes. /// internal AttributeCollection GetAttributes() { // Worst case collision scenario: we don't want the perf hit // of taking a lock, so if we collide we will query for // attributes twice. Not a big deal. // if (_attributes == null) { TypeDescriptor.Trace("Attributes : Building collection for {0}", _type.Name); // Obtaining attributes follows a very critical order: we must take care that // we merge attributes the right way. Consider this: // // [A4] // interface IBase; // // [A3] // interface IDerived; // // [A2] // class Base : IBase; // // [A1] // class Derived : Base, IDerived // // Calling GetAttributes on type Derived must merge attributes in the following // order: A1 - A4. Interfaces always lose to types, and interfaces and types // must be merged in the same order. At the same time, we must be careful // that we don't always go through reflection here, because someone could have // created a custom provider for a type. Because there is only one instance // of ReflectTypeDescriptionProvider created for typeof(object), if our code // is invoked here we can be sure that there is no custom provider for // _type all the way up the base class chain. // We cannot be sure that there is no custom provider for // interfaces that _type implements, however, because they are not derived // from _type. So, for interfaces, we must go through TypeDescriptor // again to get the interfaces attributes. // Get the type's attributes. This does not recurse up the base class chain. // We append base class attributes to this array so when walking we will // walk from Length - 1 to zero. // Attribute[] attrArray = ReflectTypeDescriptionProvider.ReflectGetAttributes(_type); Type baseType = _type.BaseType; while (baseType != null && baseType != typeof(object)) { Attribute[] baseArray = ReflectTypeDescriptionProvider.ReflectGetAttributes(baseType); Attribute[] temp = new Attribute[attrArray.Length + baseArray.Length]; Array.Copy(attrArray, 0, temp, 0, attrArray.Length); Array.Copy(baseArray, 0, temp, attrArray.Length, baseArray.Length); attrArray = temp; baseType = baseType.BaseType; } // Next, walk the type's interfaces. We append these to // the attribute array as well. // int ifaceStartIdx = attrArray.Length; Type[] interfaces = _type.GetInterfaces(); TypeDescriptor.Trace("Attributes : Walking {0} interfaces", interfaces.Length); for(int idx = 0; idx < interfaces.Length; idx++) { Type iface = interfaces[idx]; // only do this for public interfaces. // if ((iface.Attributes & (TypeAttributes.Public | TypeAttributes.NestedPublic)) != 0) { // No need to pass an instance into GetTypeDescriptor here because, if someone provided a custom // provider based on object, it already would have hit. AttributeCollection ifaceAttrs = TypeDescriptor.GetAttributes(iface); if (ifaceAttrs.Count > 0) { Attribute[] temp = new Attribute[attrArray.Length + ifaceAttrs.Count]; Array.Copy(attrArray, 0, temp, 0, attrArray.Length); ifaceAttrs.CopyTo(temp, attrArray.Length); attrArray = temp; } } } // Finally, hash all these attributes up in reverse order. // Hashtable attributeHash = new Hashtable(attrArray.Length); for (int idx = attrArray.Length -1; idx >= 0; idx--) { bool addAttr = true; if (idx >= ifaceStartIdx) { for (int ifaceSkipIdx = 0; ifaceSkipIdx < _skipInterfaceAttributeList.Length; ifaceSkipIdx++) { if (_skipInterfaceAttributeList[ifaceSkipIdx].IsInstanceOfType(attrArray[idx])) { addAttr = false; break; } } } if (addAttr) { attributeHash[attrArray[idx].TypeId] = attrArray[idx]; } } attrArray = new Attribute[attributeHash.Count]; attributeHash.Values.CopyTo(attrArray, 0); _attributes = new AttributeCollection(attrArray); } return _attributes; } ////// Retrieves the class name for our type. /// internal string GetClassName(object instance) { return _type.FullName; } ////// Retrieves the component name from the site. /// internal string GetComponentName(object instance) { IComponent comp = instance as IComponent; if (comp != null) { ISite site = comp.Site; if (site != null) { INestedSite nestedSite = site as INestedSite; if (nestedSite != null) { return nestedSite.FullName; } else { return site.Name; } } } return null; } ////// Retrieves the type converter. If instance is non-null, /// it will be used to retrieve attributes. Otherwise, _type /// will be used. /// internal TypeConverter GetConverter(object instance) { TypeConverterAttribute typeAttr = null; // For instances, the design time object for them may want to redefine the // attributes. So, we search the attribute here based on the instance. If found, // we then search on the same attribute based on type. If the two don't match, then // we cannot cache the value and must re-create every time. It is rare for a designer // to override these attributes, so we want to be smart here. // if (instance != null) { typeAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(_type)[typeof(TypeConverterAttribute)]; TypeConverterAttribute instanceAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(instance)[typeof(TypeConverterAttribute)]; if (typeAttr != instanceAttr) { Type converterType = GetTypeFromName(instanceAttr.ConverterTypeName); if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) { try { IntSecurity.FullReflection.Assert(); return (TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, _type); } finally { CodeAccessPermission.RevertAssert(); } } } } // If we got here, we return our type-based converter. // if (_converter == null) { TypeDescriptor.Trace("Converters : Building converter for {0}", _type.Name); if (typeAttr == null) { typeAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(_type)[typeof(TypeConverterAttribute)]; } if (typeAttr != null) { Type converterType = GetTypeFromName(typeAttr.ConverterTypeName); if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) { try { IntSecurity.FullReflection.Assert(); _converter = (TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, _type); } finally { CodeAccessPermission.RevertAssert(); } } } if (_converter == null) { // We did not get a converter. Traverse up the base class chain until // we find one in the stock hashtable. // _converter = (TypeConverter)ReflectTypeDescriptionProvider.SearchIntrinsicTable(IntrinsicTypeConverters, _type); Debug.Assert(_converter != null, "There is no intrinsic setup in the hashtable for the Object type"); } } return _converter; } ////// Return the default event. The default event is determined by the /// presence of a DefaultEventAttribute on the class. /// internal EventDescriptor GetDefaultEvent(object instance) { AttributeCollection attributes; if (instance != null) { attributes = TypeDescriptor.GetAttributes(instance); } else { attributes = TypeDescriptor.GetAttributes(_type); } DefaultEventAttribute attr = (DefaultEventAttribute)attributes[typeof(DefaultEventAttribute)]; if (attr != null && attr.Name != null) { if (instance != null) { return TypeDescriptor.GetEvents(instance)[attr.Name]; } else { return TypeDescriptor.GetEvents(_type)[attr.Name]; } } return null; } ////// Return the default property. /// internal PropertyDescriptor GetDefaultProperty(object instance) { AttributeCollection attributes; if (instance != null) { attributes = TypeDescriptor.GetAttributes(instance); } else { attributes = TypeDescriptor.GetAttributes(_type); } DefaultPropertyAttribute attr = (DefaultPropertyAttribute)attributes[typeof(DefaultPropertyAttribute)]; if (attr != null && attr.Name != null) { if (instance != null) { return TypeDescriptor.GetProperties(instance)[attr.Name]; } else { return TypeDescriptor.GetProperties(_type)[attr.Name]; } } return null; } ////// Retrieves the editor for the given base type. /// internal object GetEditor(object instance, Type editorBaseType) { EditorAttribute typeAttr; // For instances, the design time object for them may want to redefine the // attributes. So, we search the attribute here based on the instance. If found, // we then search on the same attribute based on type. If the two don't match, then // we cannot cache the value and must re-create every time. It is rare for a designer // to override these attributes, so we want to be smart here. // if (instance != null) { typeAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(_type), editorBaseType); EditorAttribute instanceAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(instance), editorBaseType); if (typeAttr != instanceAttr) { Type editorType = GetTypeFromName(instanceAttr.EditorTypeName); if (editorType != null && editorBaseType.IsAssignableFrom(editorType)) { return ReflectTypeDescriptionProvider.CreateInstance(editorType, _type); } } } // If we got here, we return our type-based editor. // lock(this) { for (int idx = 0; idx < _editorCount; idx++) { if (_editorTypes[idx] == editorBaseType) { return _editors[idx]; } } } // Editor is not cached yet. Look in the attributes. // object editor = null; typeAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(_type), editorBaseType); if (typeAttr != null) { Type editorType = GetTypeFromName(typeAttr.EditorTypeName); if (editorType != null && editorBaseType.IsAssignableFrom(editorType)) { editor = ReflectTypeDescriptionProvider.CreateInstance(editorType, _type); } } // Editor is not in the attributes. Search intrinsic tables. // if (editor == null) { Hashtable intrinsicEditors = ReflectTypeDescriptionProvider.GetEditorTable(editorBaseType); if (intrinsicEditors != null) { editor = ReflectTypeDescriptionProvider.SearchIntrinsicTable(intrinsicEditors, _type); } // As a quick sanity check, check to see that the editor we got back is of // the correct type. // if (editor != null && !editorBaseType.IsInstanceOfType(editor)) { Debug.Fail("Editor " + editor.GetType().FullName + " is not an instance of " + editorBaseType.FullName + " but it is in that base types table."); editor = null; } } if (editor != null) { lock(this) { if (_editorTypes == null || _editorTypes.Length == _editorCount) { int newLength = (_editorTypes == null ? 4 : _editorTypes.Length * 2); Type[] newTypes = new Type[newLength]; object[] newEditors = new object[newLength]; if (_editorTypes != null) { _editorTypes.CopyTo(newTypes, 0); _editors.CopyTo(newEditors, 0); } _editorTypes = newTypes; _editors = newEditors; _editorTypes[_editorCount] = editorBaseType; _editors[_editorCount++] = editor; } } } return editor; } ////// Helper method to return an editor attribute of the correct base type. /// private static EditorAttribute GetEditorAttribute(AttributeCollection attributes, Type editorBaseType) { foreach(Attribute attr in attributes) { EditorAttribute edAttr = attr as EditorAttribute; if (edAttr != null) { Type attrEditorBaseType = Type.GetType(edAttr.EditorBaseTypeName); if (attrEditorBaseType != null && attrEditorBaseType == editorBaseType) { return edAttr; } } } return null; } ////// Retrieves the events for this type. /// internal EventDescriptorCollection GetEvents() { // Worst case collision scenario: we don't want the perf hit // of taking a lock, so if we collide we will query for // events twice. Not a big deal. // if (_events == null) { TypeDescriptor.Trace("Events : Building collection for {0}", _type.Name); EventDescriptor[] eventArray; DictionaryeventList = new Dictionary (16); Type baseType = _type; Type objType = typeof(object); do { eventArray = ReflectGetEvents(baseType); foreach(EventDescriptor ed in eventArray) { if (!eventList.ContainsKey(ed.Name)) { eventList.Add(ed.Name, ed); } } baseType = baseType.BaseType; } while(baseType != null && baseType != objType); eventArray = new EventDescriptor[eventList.Count]; eventList.Values.CopyTo(eventArray, 0); _events = new EventDescriptorCollection(eventArray, true); } return _events; } /// /// Retrieves the properties for this type. /// internal PropertyDescriptorCollection GetProperties() { // Worst case collision scenario: we don't want the perf hit // of taking a lock, so if we collide we will query for // properties twice. Not a big deal. // if (_properties == null) { TypeDescriptor.Trace("Properties : Building collection for {0}", _type.Name); PropertyDescriptor[] propertyArray; DictionarypropertyList = new Dictionary (10); Type baseType = _type; Type objType = typeof(object); do { propertyArray = ReflectGetProperties(baseType); foreach(PropertyDescriptor p in propertyArray) { if (!propertyList.ContainsKey(p.Name)) { propertyList.Add(p.Name, p); } } baseType = baseType.BaseType; } while(baseType != null && baseType != objType); propertyArray = new PropertyDescriptor[propertyList.Count]; propertyList.Values.CopyTo(propertyArray, 0); _properties = new PropertyDescriptorCollection(propertyArray, true); } return _properties; } /// /// Retrieves a type from a name. The Assembly of the type /// that this PropertyDescriptor came from is first checked, /// then a global Type.GetType is performed. /// private Type GetTypeFromName(string typeName) { if (typeName == null || typeName.Length == 0) { return null; } int commaIndex = typeName.IndexOf(','); Type t = null; if (commaIndex == -1) { t = _type.Assembly.GetType(typeName); } if (t == null) { t = Type.GetType(typeName); } if (t == null && commaIndex != -1) { // At design time, it's possible for us to reuse // an assembly but add new types. The app domain // will cache the assembly based on identity, however, // so it could be looking in the previous version // of the assembly and not finding the type. We work // around this by looking for the non-assembly qualified // name, which causes the domain to raise a type // resolve event. // t = Type.GetType(typeName.Substring(0, commaIndex)); } return t; } ////// Refreshes the contents of this type descriptor. This does not /// actually requery, but it will clear our state so the next /// query re-populates. /// internal void Refresh() { _attributes = null; _events = null; _properties = null; _converter = null; _editors = null; _editorTypes = null; _editorCount = 0; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.ComponentModel { using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel.Design; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Security; using System.Security.Permissions; ////// This type description provider provides type information through /// reflection. Unless someone has provided a custom type description /// provider for a type or instance, or unless an instance implements /// ICustomTypeDescriptor, any query for type information will go through /// this class. There should be a single instance of this class associated /// with "object", as it can provide all type information for any type. /// [HostProtection(SharedState = true)] internal sealed class ReflectTypeDescriptionProvider : TypeDescriptionProvider { // Hastable of Type -> ReflectedTypeData. ReflectedTypeData contains all // of the type information we have gathered for a given type. // private Hashtable _typeData; // This is the signature we look for when creating types that are generic, but // want to know what type they are dealing with. Enums are a good example of this; // there is one enum converter that can work with all enums, but it needs to know // the type of enum it is dealing with. // private static Type[] _typeConstructor = new Type[] {typeof(Type)}; // This is where we store the various converters, etc for the intrinsic types. // private static Hashtable _editorTables; private static Hashtable _intrinsicTypeConverters; // For converters, etc that are bound to class attribute data, rather than a class // type, we have special key sentinel values that we put into the hash table. // private static object _intrinsicReferenceKey = new object(); private static object _intrinsicNullableKey = new object(); // The key we put into IDictionaryService to store our cache dictionary. // private static object _dictionaryKey = new object(); // This is a cache on top of core reflection. The cache // builds itself recursively, so if you ask for the properties // on Control, Component and object are also automatically filled // in. The keys to the property and event caches are types. // The keys to the attribute cache are either MemberInfos or types. // private static Hashtable _propertyCache; private static Hashtable _eventCache; private static Hashtable _attributeCache; private static Hashtable _extendedPropertyCache; // These are keys we stuff into our object cache. We use this // cache data to store extender provider info for an object. // private static readonly Guid _extenderProviderKey = Guid.NewGuid(); private static readonly Guid _extenderPropertiesKey = Guid.NewGuid(); private static readonly Guid _extenderProviderPropertiesKey = Guid.NewGuid(); // These are attribute that, when we discover them on interfaces, we do // not merge them into the attribute set for a class. private static readonly Type[] _skipInterfaceAttributeList = new Type[] { typeof(System.Runtime.InteropServices.GuidAttribute), typeof(System.Runtime.InteropServices.ComVisibleAttribute), typeof(System.Runtime.InteropServices.InterfaceTypeAttribute) }; internal static Guid ExtenderProviderKey { get { return _extenderProviderKey; } } private static object _internalSyncObject = new object(); ////// Creates a new ReflectTypeDescriptionProvider. The type is the /// type we will obtain type information for. /// internal ReflectTypeDescriptionProvider() { TypeDescriptor.Trace("Reflect : Creating ReflectTypeDescriptionProvider"); } ////// This is a table we create for intrinsic types. /// There should be entries here ONLY for intrinsic /// types, as all other types we should be able to /// add attributes directly as metadata. /// private static Hashtable IntrinsicTypeConverters { get { // It is not worth taking a lock for this -- worst case of a collision // would build two tables, one that garbage collects very quickly. // if (_intrinsicTypeConverters == null) { Hashtable temp = new Hashtable(); // Add the intrinsics // temp[typeof(bool)] = typeof(BooleanConverter); temp[typeof(byte)] = typeof(ByteConverter); temp[typeof(SByte)] = typeof(SByteConverter); temp[typeof(char)] = typeof(CharConverter); temp[typeof(double)] = typeof(DoubleConverter); temp[typeof(string)] = typeof(StringConverter); temp[typeof(int)] = typeof(Int32Converter); temp[typeof(short)] = typeof(Int16Converter); temp[typeof(long)] = typeof(Int64Converter); temp[typeof(float)] = typeof(SingleConverter); temp[typeof(UInt16)] = typeof(UInt16Converter); temp[typeof(UInt32)] = typeof(UInt32Converter); temp[typeof(UInt64)] = typeof(UInt64Converter); temp[typeof(object)] = typeof(TypeConverter); temp[typeof(void)] = typeof(TypeConverter); temp[typeof(CultureInfo)] = typeof(CultureInfoConverter); temp[typeof(DateTime)] = typeof(DateTimeConverter); temp[typeof(DateTimeOffset)] = typeof(DateTimeOffsetConverter); temp[typeof(Decimal)] = typeof(DecimalConverter); temp[typeof(TimeSpan)] = typeof(TimeSpanConverter); temp[typeof(Guid)] = typeof(GuidConverter); temp[typeof(Array)] = typeof(ArrayConverter); temp[typeof(ICollection)] = typeof(CollectionConverter); temp[typeof(Enum)] = typeof(EnumConverter); // Special cases for things that are not bound to a specific type // temp[_intrinsicReferenceKey] = typeof(ReferenceConverter); temp[_intrinsicNullableKey] = typeof(NullableConverter); _intrinsicTypeConverters = temp; } return _intrinsicTypeConverters; } } ////// Adds an editor table for the given editor base type. /// ypically, editors are specified as metadata on an object. If no metadata for a /// equested editor base type can be found on an object, however, the /// ypeDescriptor will search an editor /// able for the editor type, if one can be found. /// internal static void AddEditorTable(Type editorBaseType, Hashtable table) { if (editorBaseType == null) { throw new ArgumentNullException("editorBaseType"); } if (table == null) { Debug.Fail("COMPAT: Editor table should not be null"); // don't throw; RTM didn't so we can't do it either. } lock(_internalSyncObject) { if (_editorTables == null) { _editorTables = new Hashtable(4); } if (!_editorTables.ContainsKey(editorBaseType)) { _editorTables[editorBaseType] = table; } } } ////// CreateInstance implementation. We delegate to Activator. /// public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) { Debug.Assert(objectType != null, "Should have arg-checked before coming in here"); object obj = null; if (argTypes != null) { obj = SecurityUtils.SecureConstructorInvoke(objectType, argTypes, args, true, BindingFlags.ExactBinding); } else { if (args != null) { argTypes = new Type[args.Length]; for(int idx = 0; idx < args.Length; idx++) { if (args[idx] != null) { argTypes[idx] = args[idx].GetType(); } else { argTypes[idx] = typeof(object); } } } else { argTypes = new Type[0]; } obj = SecurityUtils.SecureConstructorInvoke(objectType, argTypes, args, true); } if (obj == null) { obj = SecurityUtils.SecureCreateInstance(objectType, args); } return obj; } ////// Helper method to create editors and type converters. This checks to see if the /// type implements a Type constructor, and if it does it invokes that ctor. /// Otherwise, it just tries to create the type. /// private static object CreateInstance(Type objectType, Type callingType) { object obj = SecurityUtils.SecureConstructorInvoke(objectType, _typeConstructor, new object[] {callingType}, false); if (obj == null) { obj = SecurityUtils.SecureCreateInstance(objectType); } return obj; } ////// Retrieves custom attributes. /// internal AttributeCollection GetAttributes(Type type) { ReflectedTypeData td = GetTypeData(type, true); return td.GetAttributes(); } ////// Our implementation of GetCache sits on top of IDictionaryService. /// public override IDictionary GetCache(object instance) { IComponent comp = instance as IComponent; if (comp != null && comp.Site != null) { IDictionaryService ds = comp.Site.GetService(typeof(IDictionaryService)) as IDictionaryService; if (ds != null) { IDictionary dict = ds.GetValue(_dictionaryKey) as IDictionary; if (dict == null) { dict = new Hashtable(); ds.SetValue(_dictionaryKey, dict); } return dict; } } return null; } ////// Retrieves the class name for our type. /// internal string GetClassName(Type type) { ReflectedTypeData td = GetTypeData(type, true); return td.GetClassName(null); } ////// Retrieves the component name from the site. /// internal string GetComponentName(Type type, object instance) { ReflectedTypeData td = GetTypeData(type, true); return td.GetComponentName(instance); } ////// Retrieves the type converter. If instance is non-null, /// it will be used to retrieve attributes. Otherwise, _type /// will be used. /// internal TypeConverter GetConverter(Type type, object instance) { ReflectedTypeData td = GetTypeData(type, true); return td.GetConverter(instance); } ////// Return the default event. The default event is determined by the /// presence of a DefaultEventAttribute on the class. /// internal EventDescriptor GetDefaultEvent(Type type, object instance) { ReflectedTypeData td = GetTypeData(type, true); return td.GetDefaultEvent(instance); } ////// Return the default property. /// internal PropertyDescriptor GetDefaultProperty(Type type, object instance) { ReflectedTypeData td = GetTypeData(type, true); return td.GetDefaultProperty(instance); } ////// Retrieves the editor for the given base type. /// internal object GetEditor(Type type, object instance, Type editorBaseType) { ReflectedTypeData td = GetTypeData(type, true); return td.GetEditor(instance, editorBaseType); } ////// Retrieves a default editor table for the given editor base type. /// private static Hashtable GetEditorTable(Type editorBaseType) { if (_editorTables == null) { lock(_internalSyncObject) { if (_editorTables == null) { _editorTables = new Hashtable(4); } } } object table = _editorTables[editorBaseType]; if (table == null) { // Before we give up, it is possible that the // class initializer for editorBaseType hasn't // actually run. // System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(editorBaseType.TypeHandle); table = _editorTables[editorBaseType]; // If the table is still null, then throw a // sentinel in there so we don't // go through this again. // if (table == null) { lock (_internalSyncObject) { table = _editorTables[editorBaseType]; if (table == null) { _editorTables[editorBaseType] = _editorTables; } } } } // Look for our sentinel value that indicates // we have already tried and failed to get // a table. // if (table == _editorTables) { table = null; } return (Hashtable)table; } ////// Retrieves the events for this type. /// internal EventDescriptorCollection GetEvents(Type type) { ReflectedTypeData td = GetTypeData(type, true); return td.GetEvents(); } ////// Retrieves custom extender attributes. We don't support /// extender attributes, so we always return an empty collection. /// internal AttributeCollection GetExtendedAttributes(object instance) { return AttributeCollection.Empty; } ////// Retrieves the class name for our type. /// internal string GetExtendedClassName(object instance) { return GetClassName(instance.GetType()); } ////// Retrieves the component name from the site. /// internal string GetExtendedComponentName(object instance) { return GetComponentName(instance.GetType(), instance); } ////// Retrieves the type converter. If instance is non-null, /// it will be used to retrieve attributes. Otherwise, _type /// will be used. /// internal TypeConverter GetExtendedConverter(object instance) { return GetConverter(instance.GetType(), instance); } ////// Return the default event. The default event is determined by the /// presence of a DefaultEventAttribute on the class. /// internal EventDescriptor GetExtendedDefaultEvent(object instance) { return null; // we don't support extended events. } ////// Return the default property. /// internal PropertyDescriptor GetExtendedDefaultProperty(object instance) { return null; // extender properties are never the default. } ////// Retrieves the editor for the given base type. /// internal object GetExtendedEditor(object instance, Type editorBaseType) { return GetEditor(instance.GetType(), instance, editorBaseType); } ////// Retrieves the events for this type. /// internal EventDescriptorCollection GetExtendedEvents(object instance) { return EventDescriptorCollection.Empty; } ////// Retrieves the properties for this type. /// internal PropertyDescriptorCollection GetExtendedProperties(object instance) { // Is this object a sited component? If not, then it // doesn't have any extender properties. // Type componentType = instance.GetType(); IComponent component = instance as IComponent; if (component == null || component.Site == null) { return PropertyDescriptorCollection.Empty; } // Check the component for extender providers. We prefer // IExtenderListService, but will use the container if that's // all we have. In either case, we check the list of extenders // against previously stored data in the object cache. If // the cache is up to date, we just return the extenders in the // cache. // IExtenderProvider[] extenders = null; IExtenderListService extenderList = component.Site.GetService(typeof(IExtenderListService)) as IExtenderListService; IDictionary cache = TypeDescriptor.GetCache(instance); if (extenderList != null) { extenders = GetExtenders(extenderList.GetExtenderProviders(), instance, cache); } else { IContainer cont = component.Site.Container; if (cont != null) { extenders = GetExtenders (cont.Components, instance, cache); } } if (extenders == null) { return PropertyDescriptorCollection.Empty; } // Ok, we have a set of extenders. Now, check to see if there // are properties already in our object cache. If there aren't, // then we will need to create them. // PropertyDescriptorCollection properties = null; if (cache != null) { properties = cache[_extenderPropertiesKey] as PropertyDescriptorCollection; } if (properties != null) { return properties; } // Unlike normal properties, it is fine for there to be properties with // duplicate names here. // ArrayList propertyList = null; for (int idx = 0; idx < extenders.Length; idx++) { PropertyDescriptor[] propertyArray = ReflectGetExtendedProperties(extenders[idx]); if (propertyList == null) { propertyList = new ArrayList(propertyArray.Length * extenders.Length); } for (int propIdx = 0; propIdx < propertyArray.Length; propIdx++) { PropertyDescriptor prop = propertyArray[propIdx]; ExtenderProvidedPropertyAttribute eppa = prop.Attributes[typeof(ExtenderProvidedPropertyAttribute)] as ExtenderProvidedPropertyAttribute; Debug.Assert(eppa != null, "Extender property " + prop.Name + " has no provider attribute. We will skip it."); if (eppa != null) { Type receiverType = eppa.ReceiverType; if (receiverType != null) { if (receiverType.IsAssignableFrom(componentType)) { propertyList.Add(prop); } } } } } // propertyHash now contains ExtendedPropertyDescriptor objects // for each extended property. // if (propertyList != null) { TypeDescriptor.Trace("Extenders : Allocating property collection for {0} properties", propertyList.Count); PropertyDescriptor[] fullArray = new PropertyDescriptor[propertyList.Count]; propertyList.CopyTo(fullArray, 0); properties = new PropertyDescriptorCollection(fullArray, true); } else { properties = PropertyDescriptorCollection.Empty; } if (cache != null) { TypeDescriptor.Trace("Extenders : caching extender results"); cache[_extenderPropertiesKey] = properties; } return properties; } ////// GetExtenders builds a list of extender providers from /// a collection of components. It validates the extenders /// against any cached collection of extenders in the /// cache. If there is a discrepancy, this will erase /// any cached extender properties from the cache and /// save the updated extender list. If there is no /// discrepancy this will simply return the cached list. /// private static IExtenderProvider[] GetExtenders(ICollection components, object instance, IDictionary cache) { bool newExtenders = false; int extenderCount = 0; IExtenderProvider[] existingExtenders = null; //CanExtend is expensive. We will remember results of CanExtend for the first 64 extenders and using "long canExtend" as a bit vector. // we want to avoid memory allocation as well so we don't use some more sophisticated data structure like an array of booleans UInt64 canExtend = 0; int maxCanExtendResults = 64; // currentExtenders is what we intend to return. If the caller passed us // the return value from IExtenderListService, components will already be // an IExtenderProvider[]. If not, then we must treat components as an // opaque collection. We spend a great deal of energy here to avoid // copying or allocating memory because this method is called every // time a component is asked for its properties. IExtenderProvider[] currentExtenders = components as IExtenderProvider[]; if (cache != null) { existingExtenders = cache[_extenderProviderKey] as IExtenderProvider[]; } if (existingExtenders == null) { newExtenders = true; } int curIdx = 0; int idx = 0; if (currentExtenders != null) { for (curIdx = 0; curIdx < currentExtenders.Length; curIdx++) { if (currentExtenders[curIdx].CanExtend(instance)) { extenderCount++; // Performance:We would like to call CanExtend as little as possible therefore we remember its result if (curIdx < maxCanExtendResults) canExtend |= (UInt64)1 << curIdx; if (!newExtenders && (idx >= existingExtenders.Length || currentExtenders[curIdx] != existingExtenders[idx++])) { newExtenders = true; } } } } else if (components != null) { foreach(object obj in components) { IExtenderProvider prov = obj as IExtenderProvider; if (prov != null && prov.CanExtend(instance)) { extenderCount++; if (curIdx < maxCanExtendResults) canExtend |= (UInt64)1<= existingExtenders.Length || prov != existingExtenders[idx++])) { newExtenders = true; } } curIdx++; } } if (existingExtenders != null && extenderCount != existingExtenders.Length) { newExtenders = true; } if (newExtenders) { TypeDescriptor.Trace("Extenders : object has new extenders : {0}", instance.GetType().Name); TypeDescriptor.Trace("Extenders : Identified {0} extender providers", extenderCount); if (currentExtenders == null || extenderCount != currentExtenders.Length) { IExtenderProvider[] newExtenderArray = new IExtenderProvider[extenderCount]; curIdx = 0; idx = 0; if (currentExtenders != null && extenderCount > 0) { while(curIdx < currentExtenders.Length) { if ((curIdx < maxCanExtendResults && (canExtend & ((UInt64)1 << curIdx)) != 0 )|| (curIdx >= maxCanExtendResults && currentExtenders[curIdx].CanExtend(instance))) { Debug.Assert(idx < extenderCount, "There are more extenders than we expect"); newExtenderArray[idx++] = currentExtenders[curIdx]; } curIdx++; } Debug.Assert(idx == extenderCount, "Wrong number of extenders"); } else if (extenderCount > 0) { IEnumerator componentEnum = components.GetEnumerator(); while(componentEnum.MoveNext()) { IExtenderProvider p = componentEnum.Current as IExtenderProvider; if (p != null && ((curIdx < maxCanExtendResults && (canExtend & ((UInt64)1 << curIdx)) != 0) || (curIdx >= maxCanExtendResults && p.CanExtend(instance)))) { Debug.Assert(idx < extenderCount, "There are more extenders than we expect"); newExtenderArray[idx++] = p; } curIdx++; } Debug.Assert(idx == extenderCount, "Wrong number of extenders"); } currentExtenders = newExtenderArray; } if (cache != null) { TypeDescriptor.Trace("Extenders : caching extender provider results"); cache[_extenderProviderKey] = currentExtenders; cache.Remove(_extenderPropertiesKey); } } else { currentExtenders = existingExtenders; } return currentExtenders; } /// /// Retrieves the owner for a property. /// internal object GetExtendedPropertyOwner(object instance, PropertyDescriptor pd) { return GetPropertyOwner(instance.GetType(), instance, pd); } ////////////////////////////////////////////////////////// ////// Provides a type descriptor for the given object. We only support this /// if the object is a component that /// public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance) { Debug.Fail("This should never be invoked. TypeDescriptionNode should wrap for us."); return null; } ////// The name of the specified component, or null if the component has no name. /// In many cases this will return the same value as GetComponentName. If the /// component resides in a nested container or has other nested semantics, it may /// return a different fully qualfied name. /// /// If not overridden, the default implementation of this method will call /// GetComponentName. /// public override string GetFullComponentName(object component) { IComponent comp = component as IComponent; if (comp != null) { INestedSite ns = comp.Site as INestedSite; if (ns != null) { return ns.FullName; } } return TypeDescriptor.GetComponentName(component); } ////// Returns an array of types we have populated metadata for that live /// in the current module. /// internal Type[] GetPopulatedTypes(Module module) { ArrayList typeList = new ArrayList();; foreach(DictionaryEntry de in _typeData) { Type type = (Type)de.Key; ReflectedTypeData typeData = (ReflectedTypeData)de.Value; if (type.Module == module && typeData.IsPopulated) { typeList.Add(type); } } return (Type[])typeList.ToArray(typeof(Type)); } ////// Retrieves the properties for this type. /// internal PropertyDescriptorCollection GetProperties(Type type) { ReflectedTypeData td = GetTypeData(type, true); return td.GetProperties(); } ////// Retrieves the owner for a property. /// internal object GetPropertyOwner(Type type, object instance, PropertyDescriptor pd) { return TypeDescriptor.GetAssociation(type, instance); } ////// Returns an Type for the given type. Since type implements IReflect, /// we just return objectType. /// public override Type GetReflectionType(Type objectType, object instance) { Debug.Assert(objectType != null, "Should have arg-checked before coming in here"); return objectType; } ////// Returns the type data for the given type, or /// null if there is no type data for the type yet and /// createIfNeeded is false. /// private ReflectedTypeData GetTypeData(Type type, bool createIfNeeded) { ReflectedTypeData td = null; if (_typeData != null) { td = (ReflectedTypeData)_typeData[type]; if (td != null) { return td; } } lock (_internalSyncObject) { if (_typeData != null) { td = (ReflectedTypeData)_typeData[type]; } if (td == null && createIfNeeded) { td = new ReflectedTypeData(type); if (_typeData == null) { _typeData = new Hashtable(); } _typeData[type] = td; } } return td; } ////// This method returns a custom type descriptor for the given type / object. /// The objectType parameter is always valid, but the instance parameter may /// be null if no instance was passed to TypeDescriptor. The method should /// return a custom type descriptor for the object. If the method is not /// interested in providing type information for the object it should /// return null. /// public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { Debug.Fail("This should never be invoked. TypeDescriptionNode should wrap for us."); return null; } ////// Retrieves a type from a name. /// private static Type GetTypeFromName(string typeName) { Type t = Type.GetType(typeName); if (t == null) { int commaIndex = typeName.IndexOf(','); if (commaIndex != -1) { // At design time, it's possible for us to reuse // an assembly but add new types. The app domain // will cache the assembly based on identity, however, // so it could be looking in the previous version // of the assembly and not finding the type. We work // around this by looking for the non-assembly qualified // name, which causes the domain to raise a type // resolve event. // t = Type.GetType(typeName.Substring(0, commaIndex)); } } return t; } ////// This method returns true if the data cache in this reflection /// type descriptor has data in it. /// internal bool IsPopulated(Type type) { ReflectedTypeData td = GetTypeData(type, false); if (td != null) { return td.IsPopulated; } return false; } ////// Static helper API around reflection to get and cache /// custom attributes. This does not recurse, but it will /// walk interfaces on the type. Interfaces are added /// to the end, so merging should be done from length - 1 /// to 0. /// private static Attribute[] ReflectGetAttributes(Type type) { if (_attributeCache == null) { lock (_internalSyncObject) { if (_attributeCache == null) { _attributeCache = new Hashtable(); } } } Attribute[] attrs = (Attribute[])_attributeCache[type]; if (attrs == null) { TypeDescriptor.Trace("Attributes : Building attributes for {0}", type.Name); // Get the type's attributes. // object[] typeAttrs = type.GetCustomAttributes(typeof(Attribute), false); attrs = new Attribute[typeAttrs.Length]; typeAttrs.CopyTo(attrs, 0); _attributeCache[type] = attrs; } return attrs; } ////// Static helper API around reflection to get and cache /// custom attributes. This does not recurse to the base class. /// internal static Attribute[] ReflectGetAttributes(MemberInfo member) { if (_attributeCache == null) { lock (_internalSyncObject) { if (_attributeCache == null) { _attributeCache = new Hashtable(); } } } Attribute[] attrs = (Attribute[])_attributeCache[member]; if (attrs == null) { // Get the member's attributes. // object[] memberAttrs = member.GetCustomAttributes(typeof(Attribute), false); attrs = new Attribute[memberAttrs.Length]; memberAttrs.CopyTo(attrs, 0); _attributeCache[member] = attrs; } return attrs; } ////// Static helper API around reflection to get and cache /// events. This does not recurse to the base class. /// private static EventDescriptor[] ReflectGetEvents(Type type) { if (_eventCache == null) { lock (_internalSyncObject) { if (_eventCache == null) { _eventCache = new Hashtable(); } } } EventDescriptor[] events = (EventDescriptor[])_eventCache[type]; if (events == null) { BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance; TypeDescriptor.Trace("Events : Building events for {0}", type.Name); // Get the type's events. Events may have their add and // remove methods individually overridden in a derived // class, but at some point in the base class chain both // methods must exist. If we find an event that doesn't // have both add and remove, we skip it here, because it // will be picked up in our base class scan. // EventInfo[] eventInfos = type.GetEvents(bindingFlags); events = new EventDescriptor[eventInfos.Length]; int eventCount = 0; for (int idx = 0; idx < eventInfos.Length; idx++) { EventInfo eventInfo = eventInfos[idx]; // GetEvents returns events that are on nonpublic types // if those types are from our assembly. Screen these. // if ((!(eventInfo.DeclaringType.IsPublic || eventInfo.DeclaringType.IsNestedPublic)) && (eventInfo.DeclaringType.Assembly == typeof(ReflectTypeDescriptionProvider).Assembly)) { Debug.Fail("Hey, assumption holds true. Rip this assert."); continue; } MethodInfo addMethod = eventInfo.GetAddMethod(); MethodInfo removeMethod = eventInfo.GetRemoveMethod(); if (addMethod != null && removeMethod != null) { events[eventCount++] = new ReflectEventDescriptor(type, eventInfo); } } if (eventCount != events.Length) { EventDescriptor[] newEvents = new EventDescriptor[eventCount]; Array.Copy(events, 0, newEvents, 0, eventCount); events = newEvents; } #if DEBUG foreach(EventDescriptor dbgEvent in events) { Debug.Assert(dbgEvent != null, "Holes in event array for type " + type); } #endif _eventCache[type] = events; } return events; } ////// This performs the actual reflection needed to discover /// extender properties. If object caching is supported this /// will maintain a cache of property descriptors on the /// extender provider. Extender properties are actually two /// property descriptors in one. There is a chunk of per-class /// data in a ReflectPropertyDescriptor that defines the /// parameter types and get and set methods of the extended property, /// and there is an ExtendedPropertyDescriptor that combines this /// with an extender provider object to create what looks like a /// normal property. ReflectGetExtendedProperties maintains two /// separate caches for these two sets: a static one for the /// ReflectPropertyDescriptor values that don't change for each /// provider instance, and a per-provider cache that contains /// the ExtendedPropertyDescriptors. /// private static PropertyDescriptor[] ReflectGetExtendedProperties(IExtenderProvider provider) { IDictionary cache = TypeDescriptor.GetCache(provider); PropertyDescriptor[] properties; if (cache != null) { properties = cache[_extenderProviderPropertiesKey] as PropertyDescriptor[]; if (properties != null) { return properties; } } // Our per-instance cache missed. We have never seen this instance of the // extender provider before. See if we can find our class-based // property store. // if (_extendedPropertyCache == null) { lock (_internalSyncObject) { if (_extendedPropertyCache == null) { _extendedPropertyCache = new Hashtable(); } } } Type providerType = provider.GetType(); ReflectPropertyDescriptor[] extendedProperties = (ReflectPropertyDescriptor[])_extendedPropertyCache[providerType]; // Our class-based property store failed as well, so we need to build up the set of // extended properties here. // if (extendedProperties == null) { AttributeCollection attributes = TypeDescriptor.GetAttributes(providerType); ArrayList extendedList = new ArrayList(attributes.Count); foreach(Attribute attr in attributes) { ProvidePropertyAttribute provideAttr = attr as ProvidePropertyAttribute; if (provideAttr != null) { Type receiverType = GetTypeFromName(provideAttr.ReceiverTypeName); if (receiverType != null) { MethodInfo getMethod = providerType.GetMethod("Get" + provideAttr.PropertyName, new Type[] {receiverType}); if (getMethod != null && !getMethod.IsStatic && getMethod.IsPublic) { MethodInfo setMethod = providerType.GetMethod("Set" + provideAttr.PropertyName, new Type[] {receiverType, getMethod.ReturnType}); if (setMethod != null && (setMethod.IsStatic || !setMethod.IsPublic)) { setMethod = null; } extendedList.Add(new ReflectPropertyDescriptor(providerType, provideAttr.PropertyName, getMethod.ReturnType, receiverType, getMethod, setMethod, null)); } } } } extendedProperties = new ReflectPropertyDescriptor[extendedList.Count]; extendedList.CopyTo(extendedProperties, 0); _extendedPropertyCache[providerType] = extendedProperties; } // Now that we have our extended properties we can build up a list of callable properties. These can be // returned to the user. // properties = new PropertyDescriptor[extendedProperties.Length]; for (int idx = 0; idx < extendedProperties.Length; idx++) { Attribute[] attrs = null; IComponent comp = provider as IComponent; if (comp == null || comp.Site == null) { attrs = new Attribute[] {DesignOnlyAttribute.Yes}; } ReflectPropertyDescriptor rpd = extendedProperties[idx]; ExtendedPropertyDescriptor epd = new ExtendedPropertyDescriptor(rpd, rpd.ExtenderGetReceiverType(), provider, attrs); properties[idx] = epd; } if (cache != null) { cache[_extenderProviderPropertiesKey] = properties; } return properties; } ////// Static helper API around reflection to get and cache /// properties. This does not recurse to the base class. /// private static PropertyDescriptor[] ReflectGetProperties(Type type) { if (_propertyCache == null) { lock(_internalSyncObject) { if (_propertyCache == null) { _propertyCache = new Hashtable(); } } } PropertyDescriptor[] properties = (PropertyDescriptor[])_propertyCache[type]; if (properties == null) { BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance; TypeDescriptor.Trace("Properties : Building properties for {0}", type.Name); // Get the type's properties. Properties may have their // get and set methods individually overridden in a derived // class, so if we find a missing method we need to walk // down the base class chain to find it. We actually merge // "new" properties of the same name, so we must preserve // the member info for each method individually. // PropertyInfo[] propertyInfos = type.GetProperties(bindingFlags); properties = new PropertyDescriptor[propertyInfos.Length]; int propertyCount = 0; for (int idx = 0; idx < propertyInfos.Length; idx++) { PropertyInfo propertyInfo = propertyInfos[idx]; // Today we do not support parameterized properties. // if (propertyInfo.GetIndexParameters().Length > 0) { continue; } MethodInfo getMethod = propertyInfo.GetGetMethod(); MethodInfo setMethod = propertyInfo.GetSetMethod(); string name = propertyInfo.Name; // If the property only overrode "set", then we don't // pick it up here. Rather, we just merge it in from // the base class list. // If a property had at least a get method, we consider it. We don't // consider write-only properties. // if (getMethod != null) { properties[propertyCount++] = new ReflectPropertyDescriptor(type, name, propertyInfo.PropertyType, propertyInfo, getMethod, setMethod, null); } } if (propertyCount != properties.Length) { PropertyDescriptor[] newProperties = new PropertyDescriptor[propertyCount]; Array.Copy(properties, 0, newProperties, 0, propertyCount); properties = newProperties; } #if DEBUG foreach(PropertyDescriptor dbgProp in properties) { Debug.Assert(dbgProp != null, "Holes in property array for type " + type); } #endif _propertyCache[type] = properties; } return properties; } ////// Refreshes the contents of this type descriptor. This does not /// actually requery, but it will clear our state so the next /// query re-populates. /// internal void Refresh(Type type) { ReflectedTypeData td = GetTypeData(type, false); if (td != null) { td.Refresh(); } } ////// Searches the provided intrinsic hashtable for a match with the object type. /// At the beginning, the hashtable contains types for the various converters. /// As this table is searched, the types for these objects /// are replaced with instances, so we only create as needed. This method /// does the search up the base class hierarchy and will create instances /// for types as needed. These instances are stored back into the table /// for the base type, and for the original component type, for fast access. /// private static object SearchIntrinsicTable(Hashtable table, Type callingType) { object hashEntry = null; // We take a lock on this table. Nothing in this code calls out to // other methods that lock, so it should be fairly safe to grab this // lock. Also, this allows multiple intrinsic tables to be searched // at once. // lock(table) { Type baseType = callingType; while (baseType != null && baseType != typeof(object)) { hashEntry = table[baseType]; // If the entry is a late-bound type, then try to // resolve it. // string typeString = hashEntry as string; if (typeString != null) { hashEntry = Type.GetType(typeString); if (hashEntry != null) { table[baseType] = hashEntry; } } if (hashEntry != null) { break; } baseType = baseType.BaseType; } // Now make a scan through each value in the table, looking for interfaces. // If we find one, see if the object implements the interface. // if (hashEntry == null) { foreach(DictionaryEntry de in table) { Type keyType = de.Key as Type; if (keyType != null && keyType.IsInterface && keyType.IsAssignableFrom(callingType)) { hashEntry = de.Value; string typeString = hashEntry as string; if (typeString != null) { hashEntry = Type.GetType(typeString); if (hashEntry != null) { table[callingType] = hashEntry; } } if (hashEntry != null) { break; } } } } // Special case converters // if (hashEntry == null) { if (callingType.IsGenericType && callingType.GetGenericTypeDefinition() == typeof(Nullable<>)) { // Check if it is a nullable value hashEntry = table[_intrinsicNullableKey]; } else if (callingType.IsInterface) { // Finally, check to see if the component type is some unknown interface. // We have a custom converter for that. hashEntry = table[_intrinsicReferenceKey]; } } // Interfaces do not derive from object, so we // must handle the case of no hash entry here. // if (hashEntry == null) { hashEntry = table[typeof(object)]; } // If the entry is a type, create an instance of it and then // replace the entry. This way we only need to create once. // We can only do this if the object doesn't want a type // in its constructor. // Type type = hashEntry as Type; if (type != null) { hashEntry = CreateInstance(type, callingType); if (type.GetConstructor(_typeConstructor) == null) { table[callingType] = hashEntry; } } } return hashEntry; } ////// This class contains all the reflection information for a /// given type. /// private class ReflectedTypeData { private Type _type; private AttributeCollection _attributes; private EventDescriptorCollection _events; private PropertyDescriptorCollection _properties; private TypeConverter _converter; private object[] _editors; private Type[] _editorTypes; private int _editorCount; internal ReflectedTypeData(Type type) { _type = type; TypeDescriptor.Trace("Reflect : Creating ReflectedTypeData for {0}", type.Name); } ////// This method returns true if the data cache in this reflection /// type descriptor has data in it. /// internal bool IsPopulated { get { return (_attributes != null) | (_events != null) | (_properties != null); } } ////// Retrieves custom attributes. /// internal AttributeCollection GetAttributes() { // Worst case collision scenario: we don't want the perf hit // of taking a lock, so if we collide we will query for // attributes twice. Not a big deal. // if (_attributes == null) { TypeDescriptor.Trace("Attributes : Building collection for {0}", _type.Name); // Obtaining attributes follows a very critical order: we must take care that // we merge attributes the right way. Consider this: // // [A4] // interface IBase; // // [A3] // interface IDerived; // // [A2] // class Base : IBase; // // [A1] // class Derived : Base, IDerived // // Calling GetAttributes on type Derived must merge attributes in the following // order: A1 - A4. Interfaces always lose to types, and interfaces and types // must be merged in the same order. At the same time, we must be careful // that we don't always go through reflection here, because someone could have // created a custom provider for a type. Because there is only one instance // of ReflectTypeDescriptionProvider created for typeof(object), if our code // is invoked here we can be sure that there is no custom provider for // _type all the way up the base class chain. // We cannot be sure that there is no custom provider for // interfaces that _type implements, however, because they are not derived // from _type. So, for interfaces, we must go through TypeDescriptor // again to get the interfaces attributes. // Get the type's attributes. This does not recurse up the base class chain. // We append base class attributes to this array so when walking we will // walk from Length - 1 to zero. // Attribute[] attrArray = ReflectTypeDescriptionProvider.ReflectGetAttributes(_type); Type baseType = _type.BaseType; while (baseType != null && baseType != typeof(object)) { Attribute[] baseArray = ReflectTypeDescriptionProvider.ReflectGetAttributes(baseType); Attribute[] temp = new Attribute[attrArray.Length + baseArray.Length]; Array.Copy(attrArray, 0, temp, 0, attrArray.Length); Array.Copy(baseArray, 0, temp, attrArray.Length, baseArray.Length); attrArray = temp; baseType = baseType.BaseType; } // Next, walk the type's interfaces. We append these to // the attribute array as well. // int ifaceStartIdx = attrArray.Length; Type[] interfaces = _type.GetInterfaces(); TypeDescriptor.Trace("Attributes : Walking {0} interfaces", interfaces.Length); for(int idx = 0; idx < interfaces.Length; idx++) { Type iface = interfaces[idx]; // only do this for public interfaces. // if ((iface.Attributes & (TypeAttributes.Public | TypeAttributes.NestedPublic)) != 0) { // No need to pass an instance into GetTypeDescriptor here because, if someone provided a custom // provider based on object, it already would have hit. AttributeCollection ifaceAttrs = TypeDescriptor.GetAttributes(iface); if (ifaceAttrs.Count > 0) { Attribute[] temp = new Attribute[attrArray.Length + ifaceAttrs.Count]; Array.Copy(attrArray, 0, temp, 0, attrArray.Length); ifaceAttrs.CopyTo(temp, attrArray.Length); attrArray = temp; } } } // Finally, hash all these attributes up in reverse order. // Hashtable attributeHash = new Hashtable(attrArray.Length); for (int idx = attrArray.Length -1; idx >= 0; idx--) { bool addAttr = true; if (idx >= ifaceStartIdx) { for (int ifaceSkipIdx = 0; ifaceSkipIdx < _skipInterfaceAttributeList.Length; ifaceSkipIdx++) { if (_skipInterfaceAttributeList[ifaceSkipIdx].IsInstanceOfType(attrArray[idx])) { addAttr = false; break; } } } if (addAttr) { attributeHash[attrArray[idx].TypeId] = attrArray[idx]; } } attrArray = new Attribute[attributeHash.Count]; attributeHash.Values.CopyTo(attrArray, 0); _attributes = new AttributeCollection(attrArray); } return _attributes; } ////// Retrieves the class name for our type. /// internal string GetClassName(object instance) { return _type.FullName; } ////// Retrieves the component name from the site. /// internal string GetComponentName(object instance) { IComponent comp = instance as IComponent; if (comp != null) { ISite site = comp.Site; if (site != null) { INestedSite nestedSite = site as INestedSite; if (nestedSite != null) { return nestedSite.FullName; } else { return site.Name; } } } return null; } ////// Retrieves the type converter. If instance is non-null, /// it will be used to retrieve attributes. Otherwise, _type /// will be used. /// internal TypeConverter GetConverter(object instance) { TypeConverterAttribute typeAttr = null; // For instances, the design time object for them may want to redefine the // attributes. So, we search the attribute here based on the instance. If found, // we then search on the same attribute based on type. If the two don't match, then // we cannot cache the value and must re-create every time. It is rare for a designer // to override these attributes, so we want to be smart here. // if (instance != null) { typeAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(_type)[typeof(TypeConverterAttribute)]; TypeConverterAttribute instanceAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(instance)[typeof(TypeConverterAttribute)]; if (typeAttr != instanceAttr) { Type converterType = GetTypeFromName(instanceAttr.ConverterTypeName); if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) { try { IntSecurity.FullReflection.Assert(); return (TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, _type); } finally { CodeAccessPermission.RevertAssert(); } } } } // If we got here, we return our type-based converter. // if (_converter == null) { TypeDescriptor.Trace("Converters : Building converter for {0}", _type.Name); if (typeAttr == null) { typeAttr = (TypeConverterAttribute)TypeDescriptor.GetAttributes(_type)[typeof(TypeConverterAttribute)]; } if (typeAttr != null) { Type converterType = GetTypeFromName(typeAttr.ConverterTypeName); if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) { try { IntSecurity.FullReflection.Assert(); _converter = (TypeConverter)ReflectTypeDescriptionProvider.CreateInstance(converterType, _type); } finally { CodeAccessPermission.RevertAssert(); } } } if (_converter == null) { // We did not get a converter. Traverse up the base class chain until // we find one in the stock hashtable. // _converter = (TypeConverter)ReflectTypeDescriptionProvider.SearchIntrinsicTable(IntrinsicTypeConverters, _type); Debug.Assert(_converter != null, "There is no intrinsic setup in the hashtable for the Object type"); } } return _converter; } ////// Return the default event. The default event is determined by the /// presence of a DefaultEventAttribute on the class. /// internal EventDescriptor GetDefaultEvent(object instance) { AttributeCollection attributes; if (instance != null) { attributes = TypeDescriptor.GetAttributes(instance); } else { attributes = TypeDescriptor.GetAttributes(_type); } DefaultEventAttribute attr = (DefaultEventAttribute)attributes[typeof(DefaultEventAttribute)]; if (attr != null && attr.Name != null) { if (instance != null) { return TypeDescriptor.GetEvents(instance)[attr.Name]; } else { return TypeDescriptor.GetEvents(_type)[attr.Name]; } } return null; } ////// Return the default property. /// internal PropertyDescriptor GetDefaultProperty(object instance) { AttributeCollection attributes; if (instance != null) { attributes = TypeDescriptor.GetAttributes(instance); } else { attributes = TypeDescriptor.GetAttributes(_type); } DefaultPropertyAttribute attr = (DefaultPropertyAttribute)attributes[typeof(DefaultPropertyAttribute)]; if (attr != null && attr.Name != null) { if (instance != null) { return TypeDescriptor.GetProperties(instance)[attr.Name]; } else { return TypeDescriptor.GetProperties(_type)[attr.Name]; } } return null; } ////// Retrieves the editor for the given base type. /// internal object GetEditor(object instance, Type editorBaseType) { EditorAttribute typeAttr; // For instances, the design time object for them may want to redefine the // attributes. So, we search the attribute here based on the instance. If found, // we then search on the same attribute based on type. If the two don't match, then // we cannot cache the value and must re-create every time. It is rare for a designer // to override these attributes, so we want to be smart here. // if (instance != null) { typeAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(_type), editorBaseType); EditorAttribute instanceAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(instance), editorBaseType); if (typeAttr != instanceAttr) { Type editorType = GetTypeFromName(instanceAttr.EditorTypeName); if (editorType != null && editorBaseType.IsAssignableFrom(editorType)) { return ReflectTypeDescriptionProvider.CreateInstance(editorType, _type); } } } // If we got here, we return our type-based editor. // lock(this) { for (int idx = 0; idx < _editorCount; idx++) { if (_editorTypes[idx] == editorBaseType) { return _editors[idx]; } } } // Editor is not cached yet. Look in the attributes. // object editor = null; typeAttr = GetEditorAttribute(TypeDescriptor.GetAttributes(_type), editorBaseType); if (typeAttr != null) { Type editorType = GetTypeFromName(typeAttr.EditorTypeName); if (editorType != null && editorBaseType.IsAssignableFrom(editorType)) { editor = ReflectTypeDescriptionProvider.CreateInstance(editorType, _type); } } // Editor is not in the attributes. Search intrinsic tables. // if (editor == null) { Hashtable intrinsicEditors = ReflectTypeDescriptionProvider.GetEditorTable(editorBaseType); if (intrinsicEditors != null) { editor = ReflectTypeDescriptionProvider.SearchIntrinsicTable(intrinsicEditors, _type); } // As a quick sanity check, check to see that the editor we got back is of // the correct type. // if (editor != null && !editorBaseType.IsInstanceOfType(editor)) { Debug.Fail("Editor " + editor.GetType().FullName + " is not an instance of " + editorBaseType.FullName + " but it is in that base types table."); editor = null; } } if (editor != null) { lock(this) { if (_editorTypes == null || _editorTypes.Length == _editorCount) { int newLength = (_editorTypes == null ? 4 : _editorTypes.Length * 2); Type[] newTypes = new Type[newLength]; object[] newEditors = new object[newLength]; if (_editorTypes != null) { _editorTypes.CopyTo(newTypes, 0); _editors.CopyTo(newEditors, 0); } _editorTypes = newTypes; _editors = newEditors; _editorTypes[_editorCount] = editorBaseType; _editors[_editorCount++] = editor; } } } return editor; } ////// Helper method to return an editor attribute of the correct base type. /// private static EditorAttribute GetEditorAttribute(AttributeCollection attributes, Type editorBaseType) { foreach(Attribute attr in attributes) { EditorAttribute edAttr = attr as EditorAttribute; if (edAttr != null) { Type attrEditorBaseType = Type.GetType(edAttr.EditorBaseTypeName); if (attrEditorBaseType != null && attrEditorBaseType == editorBaseType) { return edAttr; } } } return null; } ////// Retrieves the events for this type. /// internal EventDescriptorCollection GetEvents() { // Worst case collision scenario: we don't want the perf hit // of taking a lock, so if we collide we will query for // events twice. Not a big deal. // if (_events == null) { TypeDescriptor.Trace("Events : Building collection for {0}", _type.Name); EventDescriptor[] eventArray; DictionaryeventList = new Dictionary (16); Type baseType = _type; Type objType = typeof(object); do { eventArray = ReflectGetEvents(baseType); foreach(EventDescriptor ed in eventArray) { if (!eventList.ContainsKey(ed.Name)) { eventList.Add(ed.Name, ed); } } baseType = baseType.BaseType; } while(baseType != null && baseType != objType); eventArray = new EventDescriptor[eventList.Count]; eventList.Values.CopyTo(eventArray, 0); _events = new EventDescriptorCollection(eventArray, true); } return _events; } /// /// Retrieves the properties for this type. /// internal PropertyDescriptorCollection GetProperties() { // Worst case collision scenario: we don't want the perf hit // of taking a lock, so if we collide we will query for // properties twice. Not a big deal. // if (_properties == null) { TypeDescriptor.Trace("Properties : Building collection for {0}", _type.Name); PropertyDescriptor[] propertyArray; DictionarypropertyList = new Dictionary (10); Type baseType = _type; Type objType = typeof(object); do { propertyArray = ReflectGetProperties(baseType); foreach(PropertyDescriptor p in propertyArray) { if (!propertyList.ContainsKey(p.Name)) { propertyList.Add(p.Name, p); } } baseType = baseType.BaseType; } while(baseType != null && baseType != objType); propertyArray = new PropertyDescriptor[propertyList.Count]; propertyList.Values.CopyTo(propertyArray, 0); _properties = new PropertyDescriptorCollection(propertyArray, true); } return _properties; } /// /// Retrieves a type from a name. The Assembly of the type /// that this PropertyDescriptor came from is first checked, /// then a global Type.GetType is performed. /// private Type GetTypeFromName(string typeName) { if (typeName == null || typeName.Length == 0) { return null; } int commaIndex = typeName.IndexOf(','); Type t = null; if (commaIndex == -1) { t = _type.Assembly.GetType(typeName); } if (t == null) { t = Type.GetType(typeName); } if (t == null && commaIndex != -1) { // At design time, it's possible for us to reuse // an assembly but add new types. The app domain // will cache the assembly based on identity, however, // so it could be looking in the previous version // of the assembly and not finding the type. We work // around this by looking for the non-assembly qualified // name, which causes the domain to raise a type // resolve event. // t = Type.GetType(typeName.Substring(0, commaIndex)); } return t; } ////// Refreshes the contents of this type descriptor. This does not /// actually requery, but it will clear our state so the next /// query re-populates. /// internal void Refresh() { _attributes = null; _events = null; _properties = null; _converter = null; _editors = null; _editorTypes = null; _editorCount = 0; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XmlNode.cs
- MarkupCompiler.cs
- GZipStream.cs
- DocumentViewer.cs
- SQlBooleanStorage.cs
- SerializationInfo.cs
- SByteConverter.cs
- DataObjectMethodAttribute.cs
- XhtmlMobileTextWriter.cs
- MenuItem.cs
- HttpServerUtilityWrapper.cs
- TextHidden.cs
- BaseProcessor.cs
- QueryTask.cs
- DataGridColumnReorderingEventArgs.cs
- WebResourceAttribute.cs
- columnmapkeybuilder.cs
- DateTimeValueSerializerContext.cs
- Latin1Encoding.cs
- XmlObjectSerializerReadContextComplexJson.cs
- CompensableActivity.cs
- SessionSwitchEventArgs.cs
- Single.cs
- SamlAuthorizationDecisionStatement.cs
- PerspectiveCamera.cs
- StagingAreaInputItem.cs
- SelectionWordBreaker.cs
- XsltQilFactory.cs
- SignerInfo.cs
- COM2IDispatchConverter.cs
- codemethodreferenceexpression.cs
- AttributeData.cs
- PathFigureCollection.cs
- OledbConnectionStringbuilder.cs
- StylusPlugin.cs
- ChannelDispatcherBase.cs
- ResourcesChangeInfo.cs
- ConfigXmlAttribute.cs
- DesignerWidgets.cs
- SmtpNetworkElement.cs
- TextWriter.cs
- ContextStaticAttribute.cs
- XmlParserContext.cs
- Action.cs
- RuntimeHandles.cs
- SafeRightsManagementEnvironmentHandle.cs
- MobileCapabilities.cs
- TypeBuilderInstantiation.cs
- TabControlEvent.cs
- TypeDescriptionProvider.cs
- KnownIds.cs
- InheritanceRules.cs
- HttpsChannelFactory.cs
- SqlDataRecord.cs
- DecimalKeyFrameCollection.cs
- ConnectionManagementElement.cs
- SafeUserTokenHandle.cs
- IPPacketInformation.cs
- Repeater.cs
- ObjectItemNoOpAssemblyLoader.cs
- IndexOutOfRangeException.cs
- ScriptMethodAttribute.cs
- FilePrompt.cs
- BuildManager.cs
- OneOf.cs
- AttributeProviderAttribute.cs
- OSFeature.cs
- TypedAsyncResult.cs
- Rect3DConverter.cs
- CuspData.cs
- BaseTypeViewSchema.cs
- TextEndOfSegment.cs
- NativeMethods.cs
- AbsoluteQuery.cs
- CharacterMetricsDictionary.cs
- StorageInfo.cs
- DocumentApplication.cs
- QueryGeneratorBase.cs
- HtmlTernaryTree.cs
- CompositeDispatchFormatter.cs
- StringComparer.cs
- Underline.cs
- Base64Encoding.cs
- LexicalChunk.cs
- glyphs.cs
- RunClient.cs
- AccessorTable.cs
- TransformerInfo.cs
- SoundPlayer.cs
- RSAPKCS1SignatureDeformatter.cs
- TargetConverter.cs
- UnlockInstanceAsyncResult.cs
- FontFaceLayoutInfo.cs
- NumericExpr.cs
- ArrayConverter.cs
- ConvertEvent.cs
- RowVisual.cs
- FormViewModeEventArgs.cs
- ActivityCodeGenerator.cs
- Page.cs