The Labs \ Source Viewer \ SSCLI \ System.ComponentModel \ AttributeCollection

  1. //------------------------------------------------------------------------------
  2. // <copyright file="AttributeCollection.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System.Diagnostics.CodeAnalysis;
  16. /*
  17. This class has the HostProtectionAttribute. The purpose of this attribute is to enforce host-specific programming model guidelines, not security behavior.
  18. Suppress FxCop message - BUT REVISIT IF ADDING NEW SECURITY ATTRIBUTES.
  19. */
  20. [assembly: SuppressMessage("Microsoft.Security", "CA2112:SecuredTypesShouldNotExposeFields", Scope = "type", Target = "System.ComponentModel.AttributeCollection")]
  21. [assembly: SuppressMessage("Microsoft.Security", "CA2112:SecuredTypesShouldNotExposeFields", Scope = "type", Target = "System.ComponentModel.AttributeCollection")]
  22. [assembly: SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Scope = "member", Target = "System.ComponentModel.AttributeCollection.CopyTo(System.Array,System.Int32):System.Void")]
  23. [assembly: SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Scope = "member", Target = "System.ComponentModel.AttributeCollection.System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator")]
  24. [assembly: SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Scope = "member", Target = "System.ComponentModel.AttributeCollection.System.Collections.ICollection.get_IsSynchronized():System.Boolean")]
  25. [assembly: SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Scope = "member", Target = "System.ComponentModel.AttributeCollection.System.Collections.ICollection.get_Count():System.Int32")]
  26. [assembly: SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Scope = "member", Target = "System.ComponentModel.AttributeCollection.System.Collections.ICollection.get_SyncRoot():System.Object")]
  27. [assembly: SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "System.ComponentModel.AttributeCollection.Contains(System.Attribute):System.Boolean")]
  28. [assembly: SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "System.ComponentModel.AttributeCollection.CopyTo(System.Array,System.Int32):System.Void")]
  29. [assembly: SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "System.ComponentModel.AttributeCollection..ctor(System.Attribute[])")]
  30. [assembly: SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "System.ComponentModel.AttributeCollection.GetEnumerator():System.Collections.IEnumerator")]
  31. [assembly: SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "System.ComponentModel.AttributeCollection.get_Item(System.Type):System.Attribute")]
  32. [assembly: SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "System.ComponentModel.AttributeCollection.get_Item(System.Int32):System.Attribute")]
  33. [assembly: SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "System.ComponentModel.AttributeCollection.get_Count():System.Int32")]
  34. namespace System.ComponentModel
  35. {
  36.    
  37.     using System.Reflection;
  38.     using System.Diagnostics;
  39.     using System.Collections;
  40.    
  41.    
  42.     /// <devdoc>
  43.     /// Represents a collection of attributes.
  44.     /// </devdoc>
  45.     [System.Runtime.InteropServices.ComVisibleAttribute(true)]
  46.     [System.Security.Permissions.HostProtection(Synchronization = true)]
  47.     public class AttributeCollection : ICollection
  48.     {
  49.        
  50.         /// <devdoc>
  51.         /// An empty AttributeCollection that can used instead of creating a new one.
  52.         /// </devdoc>
  53.         public static readonly AttributeCollection Empty = new AttributeCollection((Attribute[])null);
  54.         private static Hashtable _defaultAttributes;
  55.        
  56.         private Attribute[] _attributes;
  57.        
  58.         private static object internalSyncObject = new object();
  59.        
  60.         private struct AttributeEntry
  61.         {
  62.             public Type type;
  63.             public int index;
  64.         }
  65.        
  66.         private const int FOUND_TYPES_LIMIT = 5;
  67.        
  68.         private AttributeEntry[] _foundAttributeTypes;
  69.        
  70.         private int _index = 0;
  71.        
  72.         /// <devdoc>
  73.         /// Creates a new AttributeCollection.
  74.         /// </devdoc>
  75.         public AttributeCollection(params Attribute[] attributes)
  76.         {
  77.             if (attributes == null) {
  78.                 attributes = new Attribute[0];
  79.             }
  80.             _attributes = attributes;
  81.            
  82.             for (int idx = 0; idx < attributes.Length; idx++) {
  83.                 if (attributes[idx] == null) {
  84.                     throw new ArgumentNullException("attributes");
  85.                 }
  86.             }
  87.         }
  88.        
  89.        
  90.         /// <devdoc>
  91.         /// Creates a new AttributeCollection from an existing AttributeCollection
  92.         /// </devdoc>
  93.         public static AttributeCollection FromExisting(AttributeCollection existing, params Attribute[] newAttributes)
  94.         {
  95.             if (existing == null) {
  96.                 throw new ArgumentNullException("existing");
  97.             }
  98.            
  99.             if (newAttributes == null) {
  100.                 newAttributes = new Attribute[0];
  101.             }
  102.            
  103.             Attribute[] newArray = new Attribute[existing.Count + newAttributes.Length];
  104.             int actualCount = existing.Count;
  105.             existing.CopyTo(newArray, 0);
  106.            
  107.             for (int idx = 0; idx < newAttributes.Length; idx++) {
  108.                 if (newAttributes[idx] == null) {
  109.                     throw new ArgumentNullException("newAttributes");
  110.                 }
  111.                
  112.                 // We must see if this attribute is already in the existing
  113.                 // array. If it is, we replace it.
  114.                 bool match = false;
  115.                 for (int existingIdx = 0; existingIdx < existing.Count; existingIdx++) {
  116.                     if (newArray[existingIdx].TypeId.Equals(newAttributes[idx].TypeId)) {
  117.                         match = true;
  118.                         newArray[existingIdx] = newAttributes[idx];
  119.                         break;
  120.                     }
  121.                 }
  122.                
  123.                 if (!match) {
  124.                     newArray[actualCount++] = newAttributes[idx];
  125.                 }
  126.             }
  127.            
  128.             // Now, if we collapsed some attributes, create a new array.
  129.             //
  130.            
  131.             Attribute[] attributes = null;
  132.             if (actualCount < newArray.Length) {
  133.                 attributes = new Attribute[actualCount];
  134.                 Array.Copy(newArray, 0, attributes, 0, actualCount);
  135.             }
  136.             else {
  137.                 attributes = newArray;
  138.             }
  139.            
  140.             return new AttributeCollection(attributes);
  141.         }
  142.        
  143.         /// <devdoc>
  144.         /// Gets the number of attributes.
  145.         /// </devdoc>
  146.         public int Count {
  147.             get { return _attributes.Length; }
  148.         }
  149.        
  150.         /// <devdoc>
  151.         /// Gets the attribute with the specified index number.
  152.         /// </devdoc>
  153.         public virtual Attribute this[int index]
  154.         {
  155.             get { return _attributes[index]; }
  156.         }
  157.        
  158.         /// <devdoc>
  159.         /// Gets the attribute with the specified type.
  160.         /// </devdoc>
  161.         public virtual Attribute this[Type attributeType]
  162.         {
  163.             get {
  164.                 lock (internalSyncObject) {
  165.                     // 2 passes here for perf. Really! first pass, we just
  166.                     // check equality, and if we don't find it, then we
  167.                     // do the IsAssignableFrom dance. Turns out that's
  168.                     // a relatively expensive call and we try to avoid it
  169.                     // since we rarely encounter derived attribute types
  170.                     // and this list is usually short.
  171.                     //
  172.                     if (_foundAttributeTypes == null) {
  173.                         _foundAttributeTypes = new AttributeEntry[FOUND_TYPES_LIMIT];
  174.                     }
  175.                    
  176.                     int ind = 0;
  177.                    
  178.                     for (; ind < FOUND_TYPES_LIMIT; ind++) {
  179.                         if (_foundAttributeTypes[ind].type == attributeType) {
  180.                             int index = _foundAttributeTypes[ind].index;
  181.                             if (index != -1) {
  182.                                 return _attributes[index];
  183.                             }
  184.                             else {
  185.                                 return GetDefaultAttribute(attributeType);
  186.                             }
  187.                         }
  188.                         if (_foundAttributeTypes[ind].type == null)
  189.                             break;
  190.                     }
  191.                    
  192.                     ind = _index++;
  193.                    
  194.                     if (_index >= FOUND_TYPES_LIMIT) {
  195.                         _index = 0;
  196.                     }
  197.                    
  198.                     _foundAttributeTypes[ind].type = attributeType;
  199.                    
  200.                     int count = _attributes.Length;
  201.                    
  202.                    
  203.                     for (int i = 0; i < count; i++) {
  204.                         Attribute attribute = _attributes[i];
  205.                         Type aType = attribute.GetType();
  206.                         if (aType == attributeType) {
  207.                             _foundAttributeTypes[ind].index = i;
  208.                             return attribute;
  209.                         }
  210.                     }
  211.                    
  212.                     // now check the hierarchies.
  213.                     for (int i = 0; i < count; i++) {
  214.                         Attribute attribute = _attributes[i];
  215.                         Type aType = attribute.GetType();
  216.                         if (attributeType.IsAssignableFrom(aType)) {
  217.                             _foundAttributeTypes[ind].index = i;
  218.                             return attribute;
  219.                         }
  220.                     }
  221.                    
  222.                     _foundAttributeTypes[ind].index = -1;
  223.                     return GetDefaultAttribute(attributeType);
  224.                 }
  225.             }
  226.         }
  227.        
  228.         /// <devdoc>
  229.         /// Determines if this collection of attributes has the specified attribute.
  230.         /// </devdoc>
  231.         public bool Contains(Attribute attribute)
  232.         {
  233.             Attribute attr = this[attribute.GetType()];
  234.             if (attr != null && attr.Equals(attribute)) {
  235.                 return true;
  236.             }
  237.             return false;
  238.         }
  239.        
  240.         /// <devdoc>
  241.         /// Determines if this attribute collection contains the all
  242.         /// the specified attributes in the attribute array.
  243.         /// </devdoc>
  244.         public bool Contains(Attribute[] attributes)
  245.         {
  246.            
  247.             if (attributes == null) {
  248.                 return true;
  249.             }
  250.            
  251.             for (int i = 0; i < attributes.Length; i++) {
  252.                 if (!Contains(attributes[i])) {
  253.                     return false;
  254.                 }
  255.             }
  256.            
  257.             return true;
  258.         }
  259.        
  260.         /// <devdoc>
  261.         /// Returns the default value for an attribute. This uses the following hurestic:
  262.         /// 1. It looks for a public static field named "Default".
  263.         /// </devdoc>
  264.         protected Attribute GetDefaultAttribute(Type attributeType)
  265.         {
  266.             lock (internalSyncObject) {
  267.                 if (_defaultAttributes == null) {
  268.                     _defaultAttributes = new Hashtable();
  269.                 }
  270.                
  271.                 // If we have already encountered this, use what's in the
  272.                 // table.
  273.                 if (_defaultAttributes.ContainsKey(attributeType)) {
  274.                     return (Attribute)_defaultAttributes[attributeType];
  275.                 }
  276.                
  277.                 Attribute attr = null;
  278.                
  279.                 // Nope, not in the table, so do the legwork to discover the default value.
  280.                 Type reflect = TypeDescriptor.GetReflectionType(attributeType);
  281.                 System.Reflection.FieldInfo field = reflect.GetField("Default", BindingFlags.Public | BindingFlags.Static | BindingFlags.GetField);
  282.                 if (field != null && field.IsStatic) {
  283.                     attr = (Attribute)field.GetValue(null);
  284.                 }
  285.                 else {
  286.                     ConstructorInfo ci = reflect.UnderlyingSystemType.GetConstructor(new Type[0]);
  287.                     if (ci != null) {
  288.                         attr = (Attribute)ci.Invoke(new object[0]);
  289.                        
  290.                         // If we successfully created, verify that it is the
  291.                         // default. Attributes don't have to abide by this rule.
  292.                         if (!attr.IsDefaultAttribute()) {
  293.                             attr = null;
  294.                         }
  295.                     }
  296.                 }
  297.                
  298.                 _defaultAttributes[attributeType] = attr;
  299.                 return attr;
  300.             }
  301.         }
  302.        
  303.         /// <devdoc>
  304.         /// Gets an enumerator for this collection.
  305.         /// </devdoc>
  306.         public IEnumerator GetEnumerator()
  307.         {
  308.             return _attributes.GetEnumerator();
  309.         }
  310.        
  311.         /// <devdoc>
  312.         /// Determines if a specified attribute is the same as an attribute
  313.         /// in the collection.
  314.         /// </devdoc>
  315.         public bool Matches(Attribute attribute)
  316.         {
  317.             for (int i = 0; i < _attributes.Length; i++) {
  318.                 if (_attributes[i].Match(attribute)) {
  319.                     return true;
  320.                 }
  321.             }
  322.             return false;
  323.         }
  324.        
  325.         /// <devdoc>
  326.         /// Determines if the attributes in the specified array are
  327.         /// the same as the attributes in the collection.
  328.         /// </devdoc>
  329.         public bool Matches(Attribute[] attributes)
  330.         {
  331.             for (int i = 0; i < attributes.Length; i++) {
  332.                 if (!Matches(attributes[i])) {
  333.                     return false;
  334.                 }
  335.             }
  336.            
  337.             return true;
  338.         }
  339.        
  340.         /// <internalonly/>
  341.         int ICollection.Count {
  342.             get { return Count; }
  343.         }
  344.        
  345.        
  346.         /// <internalonly/>
  347.         bool ICollection.IsSynchronized {
  348.             get { return false; }
  349.         }
  350.        
  351.         /// <internalonly/>
  352.         object ICollection.SyncRoot {
  353.             get { return null; }
  354.         }
  355.        
  356.         /// <devdoc>
  357.         /// Copies this collection to an array.
  358.         /// </devdoc>
  359.         public void CopyTo(Array array, int index)
  360.         {
  361.             Array.Copy(_attributes, 0, array, index, _attributes.Length);
  362.         }
  363.        
  364.         /// <internalonly/>
  365.         IEnumerator IEnumerable.GetEnumerator()
  366.         {
  367.             return GetEnumerator();
  368.         }
  369.     }
  370. }

Developer Fusion