using System.Diagnostics.CodeAnalysis; namespace System.Activities.Presentation.Metadata { using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Activities.Presentation.Internal.Metadata; using System.Runtime; using System.Activities.Presentation; /// /// The MetadataStore is a container of custom attribute metadata. /// Custom attributes may be defined in an attribute table and added /// to the metadata store. Once added, these attributes will appear /// in calls made to TypeDescriptor. /// public static class MetadataStore { private static object _syncLock = new object(); private static MetadataStoreProvider _objectProvider; private static Dictionary _interfaces; private static Hashtable _typeAttributeCache; [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] static MetadataStore() { TypeDescriptor.Refreshed += TypeDescriptor_Refreshed; } static void TypeDescriptor_Refreshed(RefreshEventArgs e) { _typeAttributeCache = null; } /// /// Adds the given table to the current AppDomain’s attribute store. /// Once added, calls to TypeDescriptor will use attributes defined /// in the newly added table. Multiple tables may be added to the /// attribute store. In the case of conflicts, attributes in the /// most recently added table win. /// /// The table to add /// if table is null public static void AddAttributeTable(AttributeTable table) { AddAttributeTableCore(table, false); } internal static void AddSystemAttributeTable(AttributeTable table) { AddAttributeTableCore(table, true); } private static void AddAttributeTableCore(AttributeTable table, bool isSystemAttributeTable = false) { if (table == null) throw FxTrace.Exception.ArgumentNull("table"); lock (_syncLock) { if (_objectProvider == null) { _objectProvider = new MetadataStoreProvider(table); TypeDescriptor.AddProvider(_objectProvider, typeof(object)); } else { _objectProvider.AddTable(table, isSystemAttributeTable); } foreach (Type t in table.AttributedTypes) { // If there are any interface types in the given // table, we must add providers specifically for those // types because interfaces do not derive from object and // are therefore missed by our global hook. if (t.IsInterface) { if (_interfaces == null) { _interfaces = new Dictionary(); } if (!_interfaces.ContainsKey(t)) { TypeDescriptor.AddProvider(_objectProvider, t); _interfaces.Add(t, t); } } } } // Now invalidate the types. foreach (Type t in table.AttributedTypes) { TypeDescriptor.Refresh(t); } #if DEBUG table.DebugValidateProvider(); #endif } // // This type description provider is used for all objects and // interfaces. // private class MetadataStoreProvider : TypeDescriptionProvider { private Dictionary _metadataTypeCache; private Dictionary _attributeCache; private Dictionary _descriptorCache; private AttributeTable[] _tables; private object _syncLock = new object(); internal MetadataStoreProvider(AttributeTable table) : base(TypeDescriptor.GetProvider(typeof(object))) { _tables = new AttributeTable[] { table }; } // // Called by the metadata store to add a new table to our // provider. Guarded by a lock on the metadata store. // internal void AddTable(AttributeTable table, bool isSystemAttributeTable = false) { // We don't expect a huge number of tables, // so creating a new array here is fine. Also, // this has the added benefit of allowing code // that eumerates tables to be thread-safe // without taking any locks. Caller is responsible // for ensuring AddTable is synchronized. AttributeTable[] newTables; newTables = new AttributeTable[_tables.Length + 1]; if (isSystemAttributeTable) { _tables.CopyTo(newTables, 0); newTables[newTables.Length - 1] = table; } else { _tables.CopyTo(newTables, 1); newTables[0] = table; } _tables = newTables; if (_attributeCache != null) _attributeCache.Clear(); // Clear all metadata types that will change as // a result of adding this new table if (_metadataTypeCache != null) { List toRemove = null; foreach (Type t in table.AttributedTypes) { foreach (Type cached in _metadataTypeCache.Keys) { Type realCachedType = cached.UnderlyingSystemType; if (t.IsAssignableFrom(realCachedType)) { if (toRemove == null) toRemove = new List(); toRemove.Add(realCachedType); } // if a type definition is changed, clear all types defined by this type definition. // eg. if Cat<> is changed, clear Cat, Cat etc. if (t.IsGenericTypeDefinition && realCachedType.IsGenericType && t == realCachedType.GetGenericTypeDefinition()) { if (toRemove == null) toRemove = new List(); toRemove.Add(realCachedType); } } } if (toRemove != null) { foreach (Type t in toRemove) { _metadataTypeCache.Remove(t); } } } } // // Private helper that creates an attribute collection given an array of attributes. // This does the appropriate pairing down of attributes with matching TypeIds so // the collection contains no redundant attributes. Attributes should be ordered // from most derived to least derived, so the first attribute reported wins. // private static AttributeCollection CreateAttributeCollection(Attribute[] attrArray) { Dictionary dict = new Dictionary(attrArray.Length); // Attrs array is ordered by priority, first one in // wins. int finalCount = attrArray.Length; for (int idx = 0; idx < attrArray.Length; idx++) { Attribute a = attrArray[idx]; if (dict.ContainsKey(a.TypeId)) { attrArray[idx] = null; finalCount--; } else { dict.Add(a.TypeId, a); } } Attribute[] finalArray; if (finalCount != attrArray.Length) { finalArray = new Attribute[finalCount]; int finalIdx = 0; for (int idx = 0; idx < attrArray.Length; idx++) { if (attrArray[idx] != null) { finalArray[finalIdx++] = attrArray[idx]; } } } else { finalArray = attrArray; } return new AttributeCollection(finalArray); } // // Returns a cached attribute collection for the given // object type and member. Member can be null to get // attributes for the class. // private AttributeCollection GetAttributes(Type objectType) { Fx.Assert(objectType != null, "objectType parameter should not be null"); AttributeCollection attributes; // Dictionary does not support thread-safe reads. We need to lock on // all access. lock (_syncLock) { if (_attributeCache == null) _attributeCache = new Dictionary(); if (!_attributeCache.TryGetValue(objectType, out attributes)) { attributes = CreateAttributeCollection(GetRawAttributes(objectType, null, null, false)); _attributeCache[objectType] = attributes; } } return attributes; } // // Raw API to return attributes. This is used by GetAttributes to // populate the AttributeCollection (which is cached), and by // the Attributes property on property and event descriptors (where // caching is handled by the Member Descriptor). Attributes // are returned from this ordered so the highest priority attributes // are first (first in wins). // private static Attribute[] GetRawAttributes(Type objectType, string member, MemberDescriptor parentDescriptor, bool isEvent) { Fx.Assert(objectType != null, "objectType parameter should not be null"); Type reflectType = TypeDescriptor.GetReflectionType(objectType); // There is a bug in CLR reflection that does not respect the "inherit" // flag for event or property infos. Our custom metadata type does respect // this flag and correctly does the right thing. If the object type we // are passed is not a metadata type, just use the default behavior of the // parent member descriptor. It will be right, and since we're not a metadata // type that means we have no overrides anyway. // // The reason we have to call our type with inherit, instead of just using // one code path is we need to support the interleaving of CLR and // metadata table attributes up the inheritance hierarchy. MetadataType // does that for us. if (parentDescriptor != null && !(reflectType is MetadataType)) { AttributeCollection attrs = parentDescriptor.Attributes; Attribute[] attrArray = new Attribute[attrs.Count]; // CLR property descriptor reverses attribute order. Fix it. for (int idx = 0; idx < attrArray.Length; idx++) { attrArray[idx] = attrs[attrArray.Length - idx - 1]; } return attrArray; } MemberInfo reflectMember; Type reflectMemberType = null; Attribute[] attributes; if (member == null) { reflectMember = reflectType; } else if (isEvent) { EventInfo info = null; MemberInfo[] infos = reflectType.GetMember(member, MemberTypes.Event, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); if (infos.Length > 0) { info = infos[0] as EventInfo; } reflectMember = info; if (info != null) reflectMemberType = TypeDescriptor.GetReflectionType(info.EventHandlerType); } else { PropertyInfo info = null; MemberInfo[] infos = reflectType.GetMember(member, MemberTypes.Property, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); if (infos.Length > 0) { info = infos[0] as PropertyInfo; } reflectMember = info; if (info != null) reflectMemberType = TypeDescriptor.GetReflectionType(info.PropertyType); } if (reflectMember == null) { Debug.Fail("Member " + member + " is not a member of type " + objectType.Name); attributes = new Attribute[0]; } else { // Cannot simply cast to Attribute[] Object[] attrs = reflectMember.GetCustomAttributes(typeof(Attribute), true); List attrList = new List(attrs); Hashtable cache = _typeAttributeCache; if (cache == null) { cache = new Hashtable(); _typeAttributeCache = cache; } // Get the base type attributes if we have them if (reflectMemberType != null) { reflectType = reflectMemberType; attrs = (object[])cache[reflectType]; if (attrs == null) { attrs = reflectType.GetCustomAttributes(typeof(Attribute), true); lock (cache.SyncRoot) { cache[reflectType] = attrs; } } attrList.AddRange(attrs); } // Get interface attributes too. foreach (Type iface in reflectType.GetInterfaces()) { attrs = (object[])cache[iface]; if (attrs == null) { attrs = iface.GetCustomAttributes(typeof(Attribute), false); lock (cache.SyncRoot) { cache[iface] = attrs; } } attrList.AddRange(attrs); } // Now go through the attributes and expand those that are // AttributeProviderAttributes for (int idx = 0; idx < attrList.Count; idx++) { AttributeProviderAttribute a = attrList[idx] as AttributeProviderAttribute; if (a != null) { reflectType = Type.GetType(a.TypeName); if (reflectType != null) { reflectType = TypeDescriptor.GetReflectionType(reflectType); reflectMember = reflectType; if (a.PropertyName != null && a.PropertyName.Length > 0) { MemberInfo[] infos = reflectType.GetMember(a.PropertyName); if (infos != null && infos.Length > 0) { reflectMember = infos[0]; } } attrList.AddRange(reflectMember.GetCustomAttributes(typeof(Attribute), true)); } } } attributes = new Attribute[attrList.Count]; for (int idx = 0; idx < attrList.Count; idx++) { attributes[idx] = (Attribute)attrList[idx]; } } return attributes; } // // Access to our descriptor cache // private MemberDescriptor GetCachedDescriptor(Type objectType, MemberDescriptor descriptor) { MemberDescriptor cached; DescriptorKey key = new DescriptorKey(objectType, descriptor); lock (_syncLock) { if (_descriptorCache == null || !_descriptorCache.TryGetValue(key, out cached)) { cached = null; } } return cached; } // // Access to our descriptor cache // private void CacheDescriptor(Type objectType, MemberDescriptor descriptor, MemberDescriptor cache) { lock (_syncLock) { if (_descriptorCache == null) { _descriptorCache = new Dictionary(); } DescriptorKey key = new DescriptorKey(objectType, descriptor); // Caller may ---- and this cache slot may already be allocated. // That's OK; we'll just replace it. _descriptorCache[key] = cache; } } // // Takes a collection of events and merges them with our own descriptors. // private EventDescriptorCollection MergeEvents(Type objectType, EventDescriptorCollection incoming) { EventDescriptor[] array = new EventDescriptor[incoming.Count]; for (int idx = 0; idx < array.Length; idx++) { EventDescriptor theirs = incoming[idx]; EventDescriptor ours = (EventDescriptor)GetCachedDescriptor(objectType, theirs); if (ours == null) { ours = new MetadataStoreEventDescriptor(objectType, theirs); CacheDescriptor(objectType, theirs, ours); } array[idx] = ours; } return new EventDescriptorCollection(array, true); } // // Takes a collection of properties and merges them with our own descriptors. // private PropertyDescriptorCollection MergeProperties(Type objectType, PropertyDescriptorCollection incoming) { PropertyDescriptor[] array = new PropertyDescriptor[incoming.Count]; for (int idx = 0; idx < array.Length; idx++) { PropertyDescriptor theirs = incoming[idx]; PropertyDescriptor ours = (PropertyDescriptor)GetCachedDescriptor(objectType, theirs); if (ours == null) { ours = new MetadataStorePropertyDescriptor(objectType, theirs); CacheDescriptor(objectType, theirs, ours); } array[idx] = ours; } return new PropertyDescriptorCollection(array, true); } // // Looks at objectType and returns a wrapped type if needed. The // parameter may be null, in which case this API returns null. // internal Type MergeType(Type objectType) { if (objectType == null) return null; return MergeTypeInternal(objectType, null); } // // Helper method for both MergeType and GetReflectionType // private Type MergeTypeInternal(Type objectType, object instance) { // If the incoming object type is already one of our wrapped types, // there is nothing more for us to do if (objectType is MetadataType) return objectType; Type baseReflectionType = base.GetReflectionType(objectType, instance); Type reflectionType; lock (_syncLock) { if (_metadataTypeCache == null || !_metadataTypeCache.TryGetValue(baseReflectionType, out reflectionType)) { Type objectTypeDefinition = null; if (objectType.IsGenericType && !objectType.IsGenericTypeDefinition) { objectTypeDefinition = objectType.GetGenericTypeDefinition(); } // See if we need to build a custom type for this objectType bool containsAttributes = false; foreach (AttributeTable table in _tables) { if (table.ContainsAttributes(objectType)) { containsAttributes = true; break; } if (objectTypeDefinition != null && table.ContainsAttributes(objectTypeDefinition)) { containsAttributes = true; break; } } // If we failed to find attributes quickly, we need // to check base classes and interfaces. if (!containsAttributes) { foreach (AttributeTable table in _tables) { foreach (Type t in table.AttributedTypes) { if (t.IsAssignableFrom(objectType)) { containsAttributes = true; break; } } } } // If we have a table that contains attributes for this type, we need // to wrap the type in our own reflection type. If not, we will // store baseReflectionType in the cache slot. if (containsAttributes) { reflectionType = new MetadataType(baseReflectionType, _tables, this); } else { reflectionType = baseReflectionType; } if (_metadataTypeCache == null) { _metadataTypeCache = new Dictionary(); } _metadataTypeCache[baseReflectionType] = reflectionType; } } return reflectionType; } // // This method is the metadata store's "master hook". It will return a custom // "MetadataType" for all types that have custom metadata declared in the // attribute table. By infusing our custom metadata at this low level, // everything that builds on top of reflection can be accomodated. // public override Type GetReflectionType(Type objectType, object instance) { if (objectType == null) throw FxTrace.Exception.ArgumentNull("objectType"); return MergeTypeInternal(objectType, instance); } // // Returns a custom type descriptor for the given object // public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { ICustomTypeDescriptor descriptor = base.GetTypeDescriptor(objectType, instance); descriptor = new MetadataStoreTypeDescriptor(this, objectType, descriptor); return descriptor; } // // A descriptor key is a dictionary key used by // our member descriptor cache. The key consists of a type // and a member descriptor. // private struct DescriptorKey : IEquatable { internal readonly Type Type; internal readonly MemberDescriptor Member; internal DescriptorKey(Type type, MemberDescriptor member) { Type = type; Member = member; } public override int GetHashCode() { int hash = Type.GetHashCode(); if (Member != null) { hash ^= Member.GetHashCode(); } return hash; } public override bool Equals(object obj) { return Equals((DescriptorKey)obj); } public static bool operator ==(DescriptorKey a, DescriptorKey b) { return a.Equals(b); } public static bool operator !=(DescriptorKey a, DescriptorKey b) { return !a.Equals(b); } #if DEBUG public override string ToString() { string v = Type.FullName; if (Member != null) v = string.Concat(v, ".", Member); return v; } #endif // IEquatable Members public bool Equals(DescriptorKey other) { if (Type != other.Type) return false; return object.ReferenceEquals(Member, other.Member); } } // // This type descriptor is what provides additional metadata. // We implement ICustomTypeDescriptor ourselves, rather than // derive from the helper CustomTypeDescriptor class because // we want this implementation to be built on a struct for // performance reasons. // private struct MetadataStoreTypeDescriptor : ICustomTypeDescriptor { private MetadataStoreProvider _provider; private Type _objectType; private ICustomTypeDescriptor _parent; internal MetadataStoreTypeDescriptor(MetadataStoreProvider provider, Type objectType, ICustomTypeDescriptor parent) { _provider = provider; _objectType = objectType; _parent = parent; } // ICustomTypeDescriptor Members // Calls that just forward the the parent API string ICustomTypeDescriptor.GetClassName() { return _parent.GetClassName(); } string ICustomTypeDescriptor.GetComponentName() { return _parent.GetComponentName(); } TypeConverter ICustomTypeDescriptor.GetConverter() { return _parent.GetConverter(); } EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() { return _parent.GetDefaultEvent(); } PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() { return _parent.GetDefaultProperty(); } object ICustomTypeDescriptor.GetEditor(Type editorBaseType) { return _parent.GetEditor(editorBaseType); } object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) { return _parent.GetPropertyOwner(pd); } // // Override to provide merged metadata // AttributeCollection ICustomTypeDescriptor.GetAttributes() { return _provider.GetAttributes(_objectType); } // // Override to provide merged metadata // EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) { return _provider.MergeEvents(_objectType, _parent.GetEvents(attributes)); } // // Override to provide merged metadata // EventDescriptorCollection ICustomTypeDescriptor.GetEvents() { return _provider.MergeEvents(_objectType, _parent.GetEvents()); } // // Override to provide merged metadata // PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) { return _provider.MergeProperties(_objectType, _parent.GetProperties(attributes)); } // // Override to provide merged metadata // PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() { return _provider.MergeProperties(_objectType, _parent.GetProperties()); } } // // A property descriptor that adds additional metadata to an existing // property descriptor. // private class MetadataStorePropertyDescriptor : PropertyDescriptor { private static readonly object _noValue = new object(); private static readonly object _invalidValue = new object(); private Type _objectType; private PropertyDescriptor _parent; private AttributeCollection _attributes; private Attribute[] _rawAttributes; private object _defaultValue = _invalidValue; private object _ambientValue = _invalidValue; // There are simpler base ctors we can invoke that do attribute merging for us. However, // they do it all up front instead of deferring. We want to defer until someone actually // asks for attributes. internal MetadataStorePropertyDescriptor(Type objectType, PropertyDescriptor parent) : base(parent.Name, null) { _objectType = objectType; _parent = parent; } // // Return our attribute collection. We cache it // for speed. // public override AttributeCollection Attributes { get { CheckAttributesValid(); if (_attributes == null) { _attributes = MetadataStoreProvider.CreateAttributeCollection(_rawAttributes); } return _attributes; } } // // DefaultValue and AmbientValue are two values that are used by // ReflectTypeDescriptionProvider in ResetValue(), CanResetValue(), // and ShouldSerializeValue() in such a way that by-passes any additional // values provided by the MetadataStore. As such, we manually look up // these two attributes ourselves to keep the MetadataStore functionality // intact. // private object DefaultValue { get { if (_defaultValue == _invalidValue) { DefaultValueAttribute dva = (DefaultValueAttribute)Attributes[typeof(DefaultValueAttribute)]; if (dva != null) { _defaultValue = dva.Value; } else { _defaultValue = _noValue; } } return _defaultValue; } } // // See comment for DefaultValue // private object AmbientValue { get { if (_ambientValue == _invalidValue) { AmbientValueAttribute ava = (AmbientValueAttribute)Attributes[typeof(AmbientValueAttribute)]; if (ava != null) { _ambientValue = ava.Value; } else { _ambientValue = _noValue; } } return _ambientValue; } } // // This is a little strange and merits some explanation. // We want to cache our attribute collection, but we need // to know when to invalidate the cache. MemberDescriptor // has an internal version stamp that it compares with // TypeDescriptor's metadata version and automatically invalidates // its own cached values for attributes. The trick is // we need to know when MemberDescriptor invalidated its // cached values. We do this by keying off the fact that // MemberDescriptor will call FillAttributes when its cache // needs to be repopulated. But, in oder to get MemberDescriptor // to look at its cache we must access an API that requires // cached data. AttributeArray does this in the lightest // possible way. The actual set of attributes in the array // is always an empty set, but we don't care; we only need // to access the property. The return value of the API // and the check for length are only here so the compiler // and FXCop do not complain about us calling a property // and not using the return value. The attribute array // always contains zero elements. // private bool CheckAttributesValid() { Fx.Assert(AttributeArray.Length == 0, "Attribute array should always contain zero elements"); return AttributeArray.Length == 0 && _attributes != null; } // // This method is called when we need to populate the raw set of // attributes for this property. // protected override void FillAttributes(IList attributeList) { _attributes = null; _defaultValue = _invalidValue; _ambientValue = _invalidValue; _rawAttributes = MetadataStoreProvider.GetRawAttributes(_objectType, Name, _parent, false); base.FillAttributes(attributeList); } // PropertyDescriptor API. public override bool CanResetValue(object component) { if (DefaultValue != _noValue) { object currentValue = GetValue(component); return !object.Equals(currentValue, DefaultValue); } else if (AmbientValue != _noValue) { object currentValue = GetValue(component); return !object.Equals(currentValue, AmbientValue); } else { return _parent.CanResetValue(component); } } public override void ResetValue(object component) { if (DefaultValue != _noValue) { SetValue(component, DefaultValue); } else if (AmbientValue != _noValue) { SetValue(component, AmbientValue); } else { _parent.ResetValue(component); } } public override bool ShouldSerializeValue(object component) { if (DefaultValue != _noValue) { object currentValue = GetValue(component); return !object.Equals(currentValue, DefaultValue); } else if (AmbientValue != _noValue) { object currentValue = GetValue(component); return !object.Equals(currentValue, AmbientValue); } else { return _parent.ShouldSerializeValue(component); } } public override void AddValueChanged(object component, EventHandler handler) { _parent.AddValueChanged(component, handler); } public override Type ComponentType { get { return _parent.ComponentType; } } [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Propagating the error might cause VS to crash")] [SuppressMessage("Reliability", "Reliability108", Justification = "Propagating the error might cause VS to crash")] public override object GetValue(object component) { object retValue = null; try { retValue = _parent.GetValue(component); } catch (System.Exception) { // GetValue throws an exception if Value is not available } return retValue; } public override bool IsReadOnly { get { return _parent.IsReadOnly || Attributes.Contains(ReadOnlyAttribute.Yes); } } public override Type PropertyType { get { return _parent.PropertyType; } } public override void SetValue(object component, object value) { _parent.SetValue(component, value); } public override void RemoveValueChanged(object component, EventHandler handler) { _parent.RemoveValueChanged(component, handler); } public override bool SupportsChangeEvents { get { return _parent.SupportsChangeEvents; } } } // // An event descriptor that adds additional metadata to an existing // event descriptor. // private class MetadataStoreEventDescriptor : EventDescriptor { private Type _objectType; private EventDescriptor _parent; // There are simpler base ctors we can invoke that do attribute merging for us. However, // they do it all up front instead of deferring. We want to defer until someone actually // asks for attributes. internal MetadataStoreEventDescriptor(Type objectType, EventDescriptor parent) : base(parent.Name, null) { _objectType = objectType; _parent = parent; } // // We override this so we can merge in our additional attributes. // By overriding here, we wait until someone actually asks for // attributes before merging. // protected override AttributeCollection CreateAttributeCollection() { Attribute[] attrs = MetadataStoreProvider.GetRawAttributes(_objectType, Name, _parent, true); // We must let MemberDescriptor build its attributes, even if we're going // to replace them. The reason for this is that MemberDescriptor keeps an // internal version stamp. This version stamp changes when someone adds // a new TypeDescriptionProvider. If we don't let MemberDescriptor maintain // this version stamp it won't invalidate metadata when someone adds or removes // a TypeDescriptionProvider, which can cause us to return stale data. AttributeArray = attrs; AttributeCollection attributes = base.CreateAttributeCollection(); // do not delete this attributes = MetadataStoreProvider.CreateAttributeCollection(attrs); return attributes; } // EventDescriptor API public override void AddEventHandler(object component, Delegate value) { _parent.AddEventHandler(component, value); } public override Type ComponentType { get { return _parent.ComponentType; } } public override Type EventType { get { return _parent.EventType; } } public override bool IsMulticast { get { return _parent.IsMulticast; } } public override void RemoveEventHandler(object component, Delegate value) { _parent.RemoveEventHandler(component, value); } } } // // This type is the core of our metadata store. We offer this through our type // description provider as the "reflection type" that should be used during // reflection operations. All things within TypeDescriptor will use this // type to get metadata, which gives us a big hook into their mechanism. // By hooking at this low level we can be sure to cover all of our bases. // private class MetadataType : Type { private Type _baseReflectionType; private AttributeTable[] _tables; private MetadataStoreProvider _provider; private Dictionary _memberCache; private Hashtable _seenAttributes; private AttributeMergeCache _cache; private object _syncLock = new object(); internal MetadataType(Type baseReflectionType, AttributeTable[] tables, MetadataStoreProvider provider) { _baseReflectionType = baseReflectionType; _tables = tables; _provider = provider; } // Type Forward APIs // // The majority of Type's API is just forwarded to our base reflection // type. // public override Guid GUID { get { return _baseReflectionType.GUID; } } public override Assembly Assembly { get { return _baseReflectionType.Assembly; } } public override string AssemblyQualifiedName { get { return _baseReflectionType.AssemblyQualifiedName; } } public override bool ContainsGenericParameters { get { return _baseReflectionType.ContainsGenericParameters; } } public override MethodBase DeclaringMethod { get { return _baseReflectionType.DeclaringMethod; } } public override RuntimeTypeHandle TypeHandle { get { return _baseReflectionType.TypeHandle; } } public override int GetHashCode() { return _baseReflectionType.GetHashCode(); } public override string FullName { get { return _baseReflectionType.FullName; } } public override GenericParameterAttributes GenericParameterAttributes { get { return _baseReflectionType.GenericParameterAttributes; } } public override int GenericParameterPosition { get { return _baseReflectionType.GenericParameterPosition; } } public override int GetArrayRank() { return _baseReflectionType.GetArrayRank(); } protected override TypeAttributes GetAttributeFlagsImpl() { return _baseReflectionType.Attributes; } protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) { return _baseReflectionType.GetConstructor(bindingAttr, binder, callConvention, types, modifiers); } public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) { return _baseReflectionType.GetConstructors(bindingAttr); } public override FieldInfo GetField(string name, BindingFlags bindingAttr) { return _baseReflectionType.GetField(name, bindingAttr); } public override FieldInfo[] GetFields(BindingFlags bindingAttr) { return _baseReflectionType.GetFields(bindingAttr); } protected override bool HasElementTypeImpl() { return _baseReflectionType.HasElementType; } public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters) { return _baseReflectionType.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters); } protected override bool IsArrayImpl() { return _baseReflectionType.IsArray; } protected override bool IsByRefImpl() { return _baseReflectionType.IsByRef; } protected override bool IsCOMObjectImpl() { return _baseReflectionType.IsCOMObject; } protected override bool IsPointerImpl() { return _baseReflectionType.IsPointer; } protected override bool IsPrimitiveImpl() { return _baseReflectionType.IsPrimitive; } public override Module Module { get { return _baseReflectionType.Module; } } public override string Namespace { get { return _baseReflectionType.Namespace; } } public override Type UnderlyingSystemType { get { return _baseReflectionType.UnderlyingSystemType; } } public override string Name { get { return _baseReflectionType.Name; } } public override InterfaceMapping GetInterfaceMap(Type interfaceType) { return _baseReflectionType.GetInterfaceMap(interfaceType); } public override bool IsAssignableFrom(Type c) { return _baseReflectionType.IsAssignableFrom(c); } protected override bool IsContextfulImpl() { return _baseReflectionType.IsContextful; } public override bool IsGenericParameter { get { return _baseReflectionType.IsGenericParameter; } } public override bool IsGenericType { get { return _baseReflectionType.IsGenericType; } } public override bool IsGenericTypeDefinition { get { return _baseReflectionType.IsGenericTypeDefinition; } } public override bool IsInstanceOfType(object o) { return _baseReflectionType.IsInstanceOfType(o); } protected override bool IsMarshalByRefImpl() { return _baseReflectionType.IsMarshalByRef; } public override bool IsSubclassOf(Type c) { return _baseReflectionType.IsSubclassOf(c); } protected override bool IsValueTypeImpl() { return _baseReflectionType.IsValueType; } public override Type MakeArrayType() { return _baseReflectionType.MakeArrayType(); } public override Type MakeArrayType(int rank) { return _baseReflectionType.MakeArrayType(rank); } public override Type MakeByRefType() { return _baseReflectionType.MakeByRefType(); } public override Type MakeGenericType(params Type[] typeArguments) { return _baseReflectionType.MakeGenericType(typeArguments); } public override Type MakePointerType() { return _baseReflectionType.MakePointerType(); } public override MemberTypes MemberType { get { return _baseReflectionType.MemberType; } } public override int MetadataToken { get { return _baseReflectionType.MetadataToken; } } public override Type ReflectedType { get { return _baseReflectionType.ReflectedType; } } public override System.Runtime.InteropServices.StructLayoutAttribute StructLayoutAttribute { get { return _baseReflectionType.StructLayoutAttribute; } } public override string ToString() { return _baseReflectionType.ToString(); } // Type APIs // // Wrap returned types // public override Type GetElementType() { return _provider.MergeType(_baseReflectionType.GetElementType()); } // // Wrap returned types // public override Type DeclaringType { get { return _provider.MergeType(_baseReflectionType.DeclaringType); } } // // Wrap returned types // public override Type[] FindInterfaces(TypeFilter filter, object filterCriteria) { Type[] ifaces = _baseReflectionType.FindInterfaces(filter, filterCriteria); for (int idx = 0; idx < ifaces.Length; idx++) { ifaces[idx] = _provider.MergeType(ifaces[idx]); } return ifaces; } // // Wrap returned types // public override Type BaseType { get { return _provider.MergeType(_baseReflectionType.BaseType); } } // // Wrap returned types // public override Type GetInterface(string name, bool ignoreCase) { return _provider.MergeType(_baseReflectionType.GetInterface(name, ignoreCase)); } // // Wrap returned types // public override Type[] GetInterfaces() { Type[] ifaces = _baseReflectionType.GetInterfaces(); for (int idx = 0; idx < ifaces.Length; idx++) { ifaces[idx] = _provider.MergeType(ifaces[idx]); } return ifaces; } // // Wrap returned types // public override Type GetNestedType(string name, BindingFlags bindingAttr) { return _provider.MergeType(_baseReflectionType.GetNestedType(name, bindingAttr)); } // // Wrap returned types // public override Type[] GetNestedTypes(BindingFlags bindingAttr) { Type[] ifaces = _baseReflectionType.GetNestedTypes(bindingAttr); for (int idx = 0; idx < ifaces.Length; idx++) { ifaces[idx] = _provider.MergeType(ifaces[idx]); } return ifaces; } // // Wrap returned types // public override Type[] GetGenericArguments() { Type[] ifaces = _baseReflectionType.GetGenericArguments(); for (int idx = 0; idx < ifaces.Length; idx++) { ifaces[idx] = _provider.MergeType(ifaces[idx]); } return ifaces; } // // Wrap returned types // public override Type[] GetGenericParameterConstraints() { Type[] ifaces = _baseReflectionType.GetGenericParameterConstraints(); for (int idx = 0; idx < ifaces.Length; idx++) { ifaces[idx] = _provider.MergeType(ifaces[idx]); } return ifaces; } // // Wrap returned types // public override Type GetGenericTypeDefinition() { return _provider.MergeType(_baseReflectionType.GetGenericTypeDefinition()); } // // Custom attribute access // public override object[] GetCustomAttributes(bool inherit) { return MergeAttributes(null, _baseReflectionType, inherit, ref _cache); } // // Custom attribute access // public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return MergeAttributes(attributeType, _baseReflectionType, inherit, ref _cache); } // // Custom attribute access // public override bool IsDefined(Type attributeType, bool inherit) { bool isDefined = _baseReflectionType.IsDefined(attributeType, inherit); if (!isDefined) isDefined = IsDefinedInTable(attributeType, null, inherit); return isDefined; } // // Member access // public override MemberInfo[] FindMembers(MemberTypes memberType, BindingFlags bindingAttr, MemberFilter filter, object filterCriteria) { MemberInfo[] infos = _baseReflectionType.FindMembers(memberType, bindingAttr, filter, filterCriteria); return MergeMembers(infos); } // // Member access // public override MemberInfo[] GetDefaultMembers() { MemberInfo[] infos = _baseReflectionType.GetDefaultMembers(); return MergeMembers(infos); } // // Member access // public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr) { MemberInfo[] infos = _baseReflectionType.GetMember(name, type, bindingAttr); return MergeMembers(infos); } // // Member access // public override MemberInfo[] GetMember(string name, BindingFlags bindingAttr) { MemberInfo[] infos = _baseReflectionType.GetMember(name, bindingAttr); return MergeMembers(infos); } // // Member access // public override MemberInfo[] GetMembers(BindingFlags bindingAttr) { MemberInfo[] infos = _baseReflectionType.GetMembers(bindingAttr); return MergeMembers(infos); } // // Event access // public override EventInfo GetEvent(string name, BindingFlags bindingAttr) { EventInfo info = _baseReflectionType.GetEvent(name, bindingAttr); return MergeEvent(info); } // // Event access // public override EventInfo[] GetEvents() { EventInfo[] infos = _baseReflectionType.GetEvents(); return MergeEvents(infos); } // // Event access // public override EventInfo[] GetEvents(BindingFlags bindingAttr) { EventInfo[] infos = _baseReflectionType.GetEvents(bindingAttr); return MergeEvents(infos); } // // Method access // protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) { MethodInfo info; if (types == null) { info = _baseReflectionType.GetMethod(name, bindingAttr); } else { info = _baseReflectionType.GetMethod(name, bindingAttr, binder, callConvention, types, modifiers); } if (info != null) { info = MergeMethod(info); } return info; } // // Method access // public override MethodInfo[] GetMethods(BindingFlags bindingAttr) { MethodInfo[] infos = _baseReflectionType.GetMethods(bindingAttr); return MergeMethods(infos); } // // Property access // public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) { PropertyInfo[] infos = _baseReflectionType.GetProperties(bindingAttr); return MergeProperties(infos); } // // Property access // protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) { PropertyInfo info; if (types != null) { info = _baseReflectionType.GetProperty(name, bindingAttr, binder, returnType, types, modifiers); } else { info = _baseReflectionType.GetProperty(name, bindingAttr); } return MergeProperty(info); } // Merging APIs // // Returns true if the given attribute type is defined in any attribute table. // This can take null for the member, in which case it searches type attributes. // Table is assigned at construction and read-only, so no locking required. // private bool IsDefinedInTable(Type attributeType, MemberInfo member, bool inherit) { bool isDefined = false; for (Type t = UnderlyingSystemType; t != null && !isDefined; t = t.BaseType) { foreach (AttributeTable table in _tables) { IEnumerable attrEnum; if (member == null) { attrEnum = table.GetCustomAttributes(t); } else { attrEnum = table.GetCustomAttributes(t, member); } foreach (object a in attrEnum) { if (attributeType.IsInstanceOfType(a)) { isDefined = true; break; } } if (isDefined) break; } if (!inherit) break; } return isDefined; } // // Merging of an array of attributes. This is called from // GetCustomAttributes for both types and members. Attributes // must be merged so the most derived and highest priority // attributes are first in the list. Metadata store attributes // always take higher precidence than CLR attributes. // [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] private object[] MergeAttributes(Type filterType, MemberInfo member, bool inherit, ref AttributeMergeCache cache) { Type currentType = UnderlyingSystemType; MemberInfo currentMember = member; if (cache == null) cache = new AttributeMergeCache(); if (cache.FilterType != filterType || cache.Member != member || cache.Inherit != inherit) { cache.FilterType = filterType; cache.Member = member; cache.Inherit = inherit; if (cache.Cache != null) cache.Cache.Clear(); } else if (cache.Cache != null) { // Cache is valid; return it return (object[])cache.Cache.ToArray(filterType ?? typeof(object)); } // Cache is invalid or null. Walk attributes. if (cache.Cache == null) cache.Cache = new ArrayList(); ArrayList compiledAttributes = cache.Cache; lock (_syncLock) { if (_seenAttributes == null) { _seenAttributes = new Hashtable(); } else { _seenAttributes.Clear(); } bool firstIteration = true; bool isType = member is Type; bool includeClrAttributes = (isType || currentMember.DeclaringType == currentType); while (currentType != null && currentMember != null) { foreach (object attr in MergeAttributesIterator(currentType, currentMember, includeClrAttributes)) { if (filterType != null && !filterType.IsAssignableFrom(attr.GetType())) continue; AttributeData attrData = AttributeDataCache.GetAttributeData(attr.GetType()); bool haveSeenBefore = _seenAttributes.ContainsKey(attrData.AttributeType); // Can we have more than one? if (haveSeenBefore && !attrData.AllowsMultiple) continue; // Is this attribute inheritable? if (!firstIteration && !attrData.IsInheritable) continue; // We do a scan here for TypeDescriptionProviderAttribute. Because we // are creating a custom type here and gathering metadata from // our base type, it is very important that we don't offer this attribute. // Doing so could cause TypeDescriptor to add a provider for this type // and create a cycle if (attrData.AttributeType.Equals(typeof(TypeDescriptionProviderAttribute))) continue; compiledAttributes.Add(attr); _seenAttributes[attrData.AttributeType] = attr; } // Continue? if (!inherit) break; // Advance up the type hierarchy // // Note: CLR attributes key off of currentMember. MetadataStore attributes key // off of currentType and memberName. Because we advance currentType independent of // currentMember, it is possible for the currentMember to belong to some // ancestor of currentType. As such, we wait with advancing currentMember until // currentType catches up. While we wait, we do not include the CLR attributes in // the mix because they would be added multiple times as a result. // Is currentType caught up to currentMember.DeclaringType? if (isType || currentMember.DeclaringType == currentType) { currentMember = AttributeDataCache.GetBaseMemberInfo(currentMember); } currentType = currentType.BaseType; if (isType || currentMember == null || currentMember.DeclaringType == currentType) { includeClrAttributes = true; } else { includeClrAttributes = false; } firstIteration = false; } } return (object[])compiledAttributes.ToArray(filterType ?? typeof(object)); } // // Enumerates through values contained in the attribute cache in // an order that returns the MetadataStore attributes before returning // the CLR attributes (if requested) // private IEnumerable MergeAttributesIterator(Type type, MemberInfo member, bool includeClrAttributes) { // MetadataStore uses member name string, instead of MemberInfo to store custom attributes, // so figure out what the member name is. For types, it will be null. string memberName = GetMemberName(member); // Go through the MetadataStore attributes first, as they take precedence over CLR attributes foreach (object attr in AttributeDataCache.GetMetadataStoreAttributes(type, memberName, _tables)) yield return attr; if (type.IsGenericType && !type.IsGenericTypeDefinition && !string.IsNullOrEmpty(memberName)) { foreach (object attr in AttributeDataCache.GetMetadataStoreAttributes(type.GetGenericTypeDefinition(), memberName, _tables)) yield return attr; } if (includeClrAttributes) { // Go through the CLR attributes second foreach (object attr in AttributeDataCache.GetClrAttributes(member)) yield return attr; } } // // Gets the member name from the specified MemberInfo that we use as key // to get custom attributes from the MetadataStore. Types will return null. // private static string GetMemberName(MemberInfo member) { if (member is Type) return null; // The only methods supported in metadata store are those related to // Get methods for DependencyProperties and they start with a "Get..." if (member.MemberType == MemberTypes.Method) { Fx.Assert( member.Name.StartsWith("Get", StringComparison.Ordinal) && member.Name.Length > 3, "MetadataStore expects to only see Get[Foo] or Set[Foo] MethodInfos"); return member.Name.Substring(3); } return member.Name; } // // Merging of an event. // private EventInfo MergeEvent(EventInfo info) { if (info == null) return null; MemberInfo cache; lock (_syncLock) { if (_memberCache == null || !_memberCache.TryGetValue(info, out cache)) { if (_memberCache == null) { _memberCache = new Dictionary(); } EventInfo newInfo = new MetadataEventInfo(info, this); _memberCache[info] = newInfo; info = newInfo; } else { info = (EventInfo)cache; } } return info; } // // Merging of an array of events. // private EventInfo[] MergeEvents(EventInfo[] infos) { for (int idx = 0; idx < infos.Length; idx++) { infos[idx] = MergeEvent(infos[idx]); } return infos; } // // Merging a generic member calls down to specific // merge functions based on the type of the member. // private MemberInfo MergeMember(MemberInfo info) { MethodInfo m; PropertyInfo p; EventInfo e; if ((m = info as MethodInfo) != null) { return MergeMethod(m); } else if ((p = info as PropertyInfo) != null) { return MergeProperty(p); } else if ((e = info as EventInfo) != null) { return MergeEvent(e); } return info; } // // Merging a generic member calls down to specific // merge functions based on the type of the member. // private MemberInfo[] MergeMembers(MemberInfo[] infos) { for (int idx = 0; idx < infos.Length; idx++) { infos[idx] = MergeMember(infos[idx]); } return infos; } // // Merging of a method. We only deal with // static methods in the format Get // so we can support attached properties. Otherwise, // we let the method be. // private MethodInfo MergeMethod(MethodInfo info) { if (info == null) return null; if (info.IsStatic && info.Name.StartsWith("Get", StringComparison.Ordinal)) { MemberInfo cache; lock (_syncLock) { if (_memberCache == null || !_memberCache.TryGetValue(info, out cache)) { if (_memberCache == null) { _memberCache = new Dictionary(); } MethodInfo newInfo = new MetadataMethodInfo(info, this); _memberCache[info] = newInfo; info = newInfo; } else { info = (MethodInfo)cache; } } } return info; } // // Merging of an array of methods. // private MethodInfo[] MergeMethods(MethodInfo[] infos) { for (int idx = 0; idx < infos.Length; idx++) { infos[idx] = MergeMethod(infos[idx]); } return infos; } // // Merging of a property. // private PropertyInfo MergeProperty(PropertyInfo info) { if (info == null) return null; MemberInfo cache; lock (_syncLock) { if (_memberCache == null || !_memberCache.TryGetValue(info, out cache)) { if (_memberCache == null) { _memberCache = new Dictionary(); } PropertyInfo newInfo = new MetadataPropertyInfo(info, this); _memberCache[info] = newInfo; info = newInfo; } else { info = (PropertyInfo)cache; } } return info; } // // Merging of an array of properties. // private PropertyInfo[] MergeProperties(PropertyInfo[] infos) { for (int idx = 0; idx < infos.Length; idx++) { infos[idx] = MergeProperty(infos[idx]); } return infos; } // // A simple class that holds merged attribute data. // private class AttributeMergeCache { internal Type FilterType; internal bool Inherit; internal ArrayList Cache; internal MemberInfo Member; } // // A property info that contains our custom metadata. // private class MetadataPropertyInfo : PropertyInfo { private PropertyInfo _info; private MetadataType _type; private AttributeMergeCache _cache; internal MetadataPropertyInfo(PropertyInfo info, MetadataType type) { _info = info; _type = type; } // // PropertyInfo overrides // public override PropertyAttributes Attributes { get { return _info.Attributes; } } public override bool CanRead { get { return _info.CanRead; } } public override bool CanWrite { get { return _info.CanWrite; } } public override MethodInfo[] GetAccessors(bool nonPublic) { return _info.GetAccessors(nonPublic); } public override MethodInfo GetGetMethod(bool nonPublic) { return _info.GetGetMethod(nonPublic); } public override ParameterInfo[] GetIndexParameters() { return _info.GetIndexParameters(); } public override MethodInfo GetSetMethod(bool nonPublic) { return _info.GetSetMethod(nonPublic); } public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) { return _info.GetValue(obj, invokeAttr, binder, index, culture); } public override Type PropertyType { get { return _info.PropertyType; } } public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) { _info.SetValue(obj, value, invokeAttr, binder, index, culture); } public override Type DeclaringType { get { return _info.DeclaringType; } } public override string Name { get { return _info.Name; } } public override Type ReflectedType { get { return _info.ReflectedType; } } public override bool Equals(object obj) { return object.ReferenceEquals(this, obj); } public override int GetHashCode() { return _info.GetHashCode(); } public override object GetConstantValue() { return _info.GetConstantValue(); } public override Type[] GetOptionalCustomModifiers() { return _info.GetOptionalCustomModifiers(); } public override object GetRawConstantValue() { return _info.GetRawConstantValue(); } public override Type[] GetRequiredCustomModifiers() { return _info.GetRequiredCustomModifiers(); } public override object GetValue(object obj, object[] index) { return _info.GetValue(obj, index); } public override MemberTypes MemberType { get { return _info.MemberType; } } public override int MetadataToken { get { return _info.MetadataToken; } } public override Module Module { get { return _info.Module; } } public override void SetValue(object obj, object value, object[] index) { _info.SetValue(obj, value, index); } public override string ToString() { return _info.ToString(); } // // Merges our custom attributes in with those of the member info. // public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return _type.MergeAttributes(attributeType, _info, inherit, ref _cache); } // // Merges our custom attributes in with those of the member info. // public override object[] GetCustomAttributes(bool inherit) { return _type.MergeAttributes(null, _info, inherit, ref _cache); } // // Determines if an attribute exists in the member info // or in our own code. // public override bool IsDefined(Type attributeType, bool inherit) { bool isDefined = _info.IsDefined(attributeType, inherit); if (!isDefined) isDefined = _type.IsDefinedInTable(attributeType, _info, inherit); return isDefined; } } // // An EventInfo that provides our custom attributes. // private class MetadataEventInfo : EventInfo { private EventInfo _info; private MetadataType _type; private AttributeMergeCache _cache; internal MetadataEventInfo(EventInfo info, MetadataType type) { _info = info; _type = type; } // // EventInfo overrides // public override EventAttributes Attributes { get { return _info.Attributes; } } public override string Name { get { return _info.Name; } } public override Type ReflectedType { get { return _info.ReflectedType; } } public override bool Equals(object obj) { return object.ReferenceEquals(this, obj); } public override int GetHashCode() { return _info.GetHashCode(); } public override MethodInfo[] GetOtherMethods(bool nonPublic) { return _info.GetOtherMethods(nonPublic); } public override MemberTypes MemberType { get { return _info.MemberType; } } public override int MetadataToken { get { return _info.MetadataToken; } } public override Module Module { get { return _info.Module; } } public override string ToString() { return _info.ToString(); } public override MethodInfo GetAddMethod(bool nonPublic) { return _info.GetAddMethod(nonPublic); } public override MethodInfo GetRaiseMethod(bool nonPublic) { return _info.GetRaiseMethod(nonPublic); } public override MethodInfo GetRemoveMethod(bool nonPublic) { return _info.GetRemoveMethod(nonPublic); } public override Type DeclaringType { get { return _info.DeclaringType; } } // // Merges our custom attributes in with those of the member info. // public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return _type.MergeAttributes(attributeType, _info, inherit, ref _cache); } // // Merges our custom attributes in with those of the member info. // public override object[] GetCustomAttributes(bool inherit) { return _type.MergeAttributes(null, _info, inherit, ref _cache); } // // Determines if an attribute exists in the member info // or in our own code. // public override bool IsDefined(Type attributeType, bool inherit) { bool isDefined = _info.IsDefined(attributeType, inherit); if (!isDefined) isDefined = _type.IsDefinedInTable(attributeType, _info, inherit); return isDefined; } } // // A MethodInfo that provides our custom attributes. // private class MetadataMethodInfo : MethodInfo { private MethodInfo _info; private MetadataType _type; private AttributeMergeCache _cache; internal MetadataMethodInfo(MethodInfo info, MetadataType type) { _info = info; _type = type; } // // MethodInfo overrides // public override ICustomAttributeProvider ReturnTypeCustomAttributes { get { return _info.ReturnTypeCustomAttributes; } } public override MethodAttributes Attributes { get { return _info.Attributes; } } public override MethodImplAttributes GetMethodImplementationFlags() { return _info.GetMethodImplementationFlags(); } public override ParameterInfo[] GetParameters() { return _info.GetParameters(); } public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) { return _info.Invoke(obj, invokeAttr, binder, parameters, culture); } public override RuntimeMethodHandle MethodHandle { get { return _info.MethodHandle; } } public override Type DeclaringType { get { return _info.DeclaringType; } } public override string Name { get { return _info.Name; } } public override Type ReflectedType { get { return _info.ReflectedType; } } public override bool Equals(object obj) { return object.ReferenceEquals(this, obj); } public override int GetHashCode() { return _info.GetHashCode(); } public override CallingConventions CallingConvention { get { return _info.CallingConvention; } } public override bool ContainsGenericParameters { get { return _info.ContainsGenericParameters; } } public override MethodInfo GetBaseDefinition() { return _info.GetBaseDefinition(); } public override Type[] GetGenericArguments() { return _info.GetGenericArguments(); } public override MethodInfo GetGenericMethodDefinition() { return _info.GetGenericMethodDefinition(); } public override MethodBody GetMethodBody() { return _info.GetMethodBody(); } public override bool IsGenericMethod { get { return _info.IsGenericMethod; } } public override bool IsGenericMethodDefinition { get { return _info.IsGenericMethodDefinition; } } public override MethodInfo MakeGenericMethod(params Type[] typeArguments) { return _info.MakeGenericMethod(typeArguments); } public override MemberTypes MemberType { get { return _info.MemberType; } } public override int MetadataToken { get { return _info.MetadataToken; } } public override Module Module { get { return _info.Module; } } public override ParameterInfo ReturnParameter { get { return _info.ReturnParameter; } } public override Type ReturnType { get { return _info.ReturnType; } } public override string ToString() { return _info.ToString(); } // // Merges our custom attributes in with those of the member info. // public override object[] GetCustomAttributes(Type attributeType, bool inherit) { return _type.MergeAttributes(attributeType, _info, inherit, ref _cache); } // // Merges our custom attributes in with those of the member info. // public override object[] GetCustomAttributes(bool inherit) { return _type.MergeAttributes(null, _info, inherit, ref _cache); } // // Determines if an attribute exists in the member info // or in our own code. // public override bool IsDefined(Type attributeType, bool inherit) { bool isDefined = _info.IsDefined(attributeType, inherit); if (!isDefined) isDefined = _type.IsDefinedInTable(attributeType, _info, inherit); return isDefined; } } } } }