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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="MemberDescriptor.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. /*
  16. */
  17. namespace System.ComponentModel
  18. {
  19.    
  20.     using Microsoft.Win32;
  21.     using System;
  22.     using System.Collections;
  23.     using System.ComponentModel.Design;
  24.     using System.Diagnostics;
  25.     using System.Reflection;
  26.     using System.Security.Permissions;
  27.    
  28.     /// <devdoc>
  29.     /// <para>
  30.     /// Declares an array of attributes for a member and defines
  31.     /// the properties and methods that give you access to the attributes in the array.
  32.     /// All attributes must derive from <see cref='System.Attribute'/>.
  33.     /// </para>
  34.     /// </devdoc>
  35.     [HostProtection(SharedState = true)]
  36.     [System.Runtime.InteropServices.ComVisible(true)]
  37.     public abstract class MemberDescriptor
  38.     {
  39.         private string name;
  40.         private string displayName;
  41.         private int nameHash;
  42.         private AttributeCollection attributeCollection;
  43.         private Attribute[] attributes;
  44.         private Attribute[] originalAttributes;
  45.         private bool attributesFiltered = false;
  46.         private bool attributesFilled = false;
  47.         private int metadataVersion;
  48.         private string category;
  49.         private string description;
  50.        
  51.        
  52.         /// <devdoc>
  53.         /// <para>
  54.         /// Initializes a new instance of the <see cref='System.ComponentModel.MemberDescriptor'/> class with the specified <paramref name="name
  55.         /// "/> and no
  56.         /// attributes.
  57.         /// </para>
  58.         /// </devdoc>
  59.         protected MemberDescriptor(string name) : this(name, null)
  60.         {
  61.         }
  62.        
  63.         /// <devdoc>
  64.         /// <para>
  65.         /// Initializes a new instance of the <see cref='System.ComponentModel.MemberDescriptor'/> class with the specified <paramref name="name"/>
  66.         /// and <paramref name="attributes "/>
  67.         /// array.
  68.         /// </para>
  69.         /// </devdoc>
  70.         protected MemberDescriptor(string name, Attribute[] attributes)
  71.         {
  72.             try {
  73.                 if (name == null || name.Length == 0) {
  74.                     throw new ArgumentException(SR.GetString(SR.InvalidMemberName));
  75.                 }
  76.                 this.name = name;
  77.                 this.displayName = name;
  78.                 this.nameHash = name.GetHashCode();
  79.                 if (attributes != null) {
  80.                     this.attributes = attributes;
  81.                     attributesFiltered = false;
  82.                 }
  83.                
  84.                 this.originalAttributes = this.attributes;
  85.             }
  86.             catch (Exception t) {
  87.                 Debug.Fail(t.ToString());
  88.                 throw t;
  89.             }
  90.         }
  91.        
  92.         /// <devdoc>
  93.         /// <para>
  94.         /// Initializes a new instance of the <see cref='System.ComponentModel.MemberDescriptor'/> class with the specified <see cref='System.ComponentModel.MemberDescriptor'/>.
  95.         /// </para>
  96.         /// </devdoc>
  97.         protected MemberDescriptor(MemberDescriptor descr)
  98.         {
  99.             this.name = descr.Name;
  100.             this.displayName = this.name;
  101.             this.nameHash = name.GetHashCode();
  102.            
  103.             this.attributes = new Attribute[descr.Attributes.Count];
  104.             descr.Attributes.CopyTo(this.attributes, 0);
  105.            
  106.             attributesFiltered = true;
  107.            
  108.             this.originalAttributes = this.attributes;
  109.         }
  110.        
  111.         /// <devdoc>
  112.         /// <para>
  113.         /// Initializes a new instance of the <see cref='System.ComponentModel.MemberDescriptor'/> class with the name in the specified
  114.         /// <see cref='System.ComponentModel.MemberDescriptor'/> and the attributes
  115.         /// in both the old <see cref='System.ComponentModel.MemberDescriptor'/> and the <see cref='System.Attribute'/> array.
  116.         /// </para>
  117.         /// </devdoc>
  118.         protected MemberDescriptor(MemberDescriptor oldMemberDescriptor, Attribute[] newAttributes)
  119.         {
  120.             this.name = oldMemberDescriptor.Name;
  121.             this.displayName = oldMemberDescriptor.DisplayName;
  122.             this.nameHash = name.GetHashCode();
  123.            
  124.             ArrayList newArray = new ArrayList();
  125.            
  126.             if (oldMemberDescriptor.Attributes.Count != 0) {
  127.                 foreach (object o in oldMemberDescriptor.Attributes) {
  128.                     newArray.Add(o);
  129.                 }
  130.             }
  131.            
  132.             if (newAttributes != null) {
  133.                 foreach (object o in newAttributes) {
  134.                     newArray.Add(o);
  135.                 }
  136.             }
  137.            
  138.             this.attributes = new Attribute[newArray.Count];
  139.             newArray.CopyTo(this.attributes, 0);
  140.             attributesFiltered = false;
  141.            
  142.             this.originalAttributes = this.attributes;
  143.         }
  144.        
  145.         /// <devdoc>
  146.         /// <para>
  147.         /// Gets or sets an array of
  148.         /// attributes.
  149.         /// </para>
  150.         /// </devdoc>
  151.         protected virtual Attribute[] AttributeArray {
  152.             get {
  153.                 CheckAttributesValid();
  154.                 FilterAttributesIfNeeded();
  155.                 return attributes;
  156.             }
  157.             set {
  158.                 lock (this) {
  159.                     attributes = value;
  160.                     originalAttributes = value;
  161.                     attributesFiltered = false;
  162.                     attributeCollection = null;
  163.                 }
  164.             }
  165.         }
  166.        
  167.         /// <devdoc>
  168.         /// <para>
  169.         /// Gets the collection of attributes for this member.
  170.         /// </para>
  171.         /// </devdoc>
  172.         public virtual AttributeCollection Attributes {
  173.             get {
  174.                 CheckAttributesValid();
  175.                 if (attributeCollection == null) {
  176.                     attributeCollection = CreateAttributeCollection();
  177.                 }
  178.                 return attributeCollection;
  179.             }
  180.         }
  181.        
  182.         /// <devdoc>
  183.         /// <para>
  184.         /// Gets the name of the category that the
  185.         /// member
  186.         /// belongs to, as specified in the <see cref='System.ComponentModel.CategoryAttribute'/>.
  187.         /// </para>
  188.         /// </devdoc>
  189.         public virtual string Category {
  190.             get {
  191.                 if (category == null) {
  192.                     category = ((CategoryAttribute)Attributes[typeof(CategoryAttribute)]).Category;
  193.                 }
  194.                 return category;
  195.             }
  196.         }
  197.        
  198.         /// <devdoc>
  199.         /// <para>
  200.         /// Gets the description of
  201.         /// the member as specified in the <see cref='System.ComponentModel.DescriptionAttribute'/>.
  202.         /// </para>
  203.         /// </devdoc>
  204.         public virtual string Description {
  205.             get {
  206.                 if (description == null) {
  207.                     description = ((DescriptionAttribute)Attributes[typeof(DescriptionAttribute)]).Description;
  208.                 }
  209.                 return description;
  210.             }
  211.         }
  212.        
  213.         /// <devdoc>
  214.         /// <para>
  215.         /// Gets a value indicating whether the member is browsable as specified in the
  216.         /// <see cref='System.ComponentModel.BrowsableAttribute'/>.
  217.         /// </para>
  218.         /// </devdoc>
  219.         public virtual bool IsBrowsable {
  220.             get { return ((BrowsableAttribute)Attributes[typeof(BrowsableAttribute)]).Browsable; }
  221.         }
  222.        
  223.         /// <devdoc>
  224.         /// <para>
  225.         /// Gets the
  226.         /// name of the member.
  227.         /// </para>
  228.         /// </devdoc>
  229.         public virtual string Name {
  230.             get {
  231.                 if (name == null) {
  232.                     return "";
  233.                 }
  234.                 return name;
  235.             }
  236.         }
  237.        
  238.         /// <devdoc>
  239.         /// <para>
  240.         /// Gets the hash
  241.         /// code for the name of the member as specified in <see cref='System.String.GetHashCode'/>.
  242.         /// </para>
  243.         /// </devdoc>
  244.         protected virtual int NameHashCode {
  245.             get { return nameHash; }
  246.         }
  247.        
  248.         /// <devdoc>
  249.         /// <para>
  250.         /// Determines whether this member should be set only at
  251.         /// design time as specified in the <see cref='System.ComponentModel.DesignOnlyAttribute'/>.
  252.         /// </para>
  253.         /// </devdoc>
  254.         public virtual bool DesignTimeOnly {
  255.             get { return (DesignOnlyAttribute.Yes.Equals(Attributes[typeof(DesignOnlyAttribute)])); }
  256.         }
  257.        
  258.         /// <devdoc>
  259.         /// <para>
  260.         /// Gets the name that can be displayed in a window like a
  261.         /// properties window.
  262.         /// </para>
  263.         /// </devdoc>
  264.         public virtual string DisplayName {
  265.             get {
  266.                 DisplayNameAttribute displayNameAttr = Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
  267.                 if (displayNameAttr == null || displayNameAttr.IsDefaultAttribute()) {
  268.                     return displayName;
  269.                 }
  270.                 return displayNameAttr.DisplayName;
  271.             }
  272.         }
  273.        
  274.         /// <devdoc>
  275.         /// Called each time we access the attribtes on
  276.         /// this member descriptor to give deriving classes
  277.         /// a chance to change them on the fly.
  278.         /// </devdoc>
  279.         private void CheckAttributesValid()
  280.         {
  281.             if (attributesFiltered) {
  282.                 if (metadataVersion != TypeDescriptor.MetadataVersion) {
  283.                     attributesFilled = false;
  284.                     attributesFiltered = false;
  285.                     attributeCollection = null;
  286.                 }
  287.             }
  288.         }
  289.        
  290.         /// <include file='doc\MemberDescriptor.uex' path='docs/doc[@for="MemberDescriptor.CreateAttributeCollection"]/*' />
  291.         /// <devdoc>
  292.         /// <para>
  293.         /// Creates a collection of attributes using the
  294.         /// array of attributes that you passed to the constructor.
  295.         /// </para>
  296.         /// </devdoc>
  297.         protected virtual AttributeCollection CreateAttributeCollection()
  298.         {
  299.             return new AttributeCollection(AttributeArray);
  300.         }
  301.        
  302.         /// <devdoc>
  303.         /// <para>
  304.         /// Compares this instance to the specified <see cref='System.ComponentModel.MemberDescriptor'/> to see if they are equivalent.
  305.         /// NOTE: If you make a change here, you likely need to change GetHashCode() as well.
  306.         /// </para>
  307.         /// </devdoc>
  308.         public override bool Equals(object obj)
  309.         {
  310.             if (this == obj) {
  311.                 return true;
  312.             }
  313.             if (obj == null) {
  314.                 return false;
  315.             }
  316.            
  317.             if (obj.GetType() != GetType()) {
  318.                 return false;
  319.             }
  320.            
  321.             MemberDescriptor mdObj = (MemberDescriptor)obj;
  322.             FilterAttributesIfNeeded();
  323.             mdObj.FilterAttributesIfNeeded();
  324.            
  325.             if (mdObj.nameHash != nameHash) {
  326.                 return false;
  327.             }
  328.            
  329.             if ((mdObj.category == null) != (category == null) || (category != null && !mdObj.category.Equals(category))) {
  330.                 return false;
  331.             }
  332.            
  333.             if ((mdObj.description == null) != (description == null) || (description != null && !mdObj.category.Equals(description))) {
  334.                 return false;
  335.             }
  336.            
  337.             if ((mdObj.attributes == null) != (attributes == null)) {
  338.                 return false;
  339.             }
  340.            
  341.             bool sameAttrs = true;
  342.            
  343.             if (attributes != null) {
  344.                 if (attributes.Length != mdObj.attributes.Length) {
  345.                     return false;
  346.                 }
  347.                 for (int i = 0; i < attributes.Length; i++) {
  348.                     if (!attributes[i].Equals(mdObj.attributes[i])) {
  349.                         sameAttrs = false;
  350.                         break;
  351.                     }
  352.                 }
  353.             }
  354.             return sameAttrs;
  355.         }
  356.        
  357.         /// <devdoc>
  358.         /// <para>
  359.         /// In an inheriting class, adds the attributes of the inheriting class to the
  360.         /// specified list of attributes in the parent class. For duplicate attributes,
  361.         /// the last one added to the list will be kept.
  362.         /// </para>
  363.         /// </devdoc>
  364.         protected virtual void FillAttributes(IList attributeList)
  365.         {
  366.             if (originalAttributes != null) {
  367.                 foreach (Attribute attr in originalAttributes) {
  368.                     attributeList.Add(attr);
  369.                 }
  370.             }
  371.         }
  372.        
  373.         private void FilterAttributesIfNeeded()
  374.         {
  375.             if (!attributesFiltered) {
  376.                 IList list;
  377.                
  378.                 if (!attributesFilled) {
  379.                     list = new ArrayList();
  380.                     try {
  381.                         FillAttributes(list);
  382.                     }
  383.                     catch (Exception e) {
  384.                         Debug.Fail(name + ">>" + e.ToString());
  385.                     }
  386.                 }
  387.                 else {
  388.                     list = new ArrayList(attributes);
  389.                 }
  390.                
  391.                 Hashtable hash = new Hashtable(list.Count);
  392.                
  393.                 foreach (Attribute attr in list) {
  394.                     hash[attr.TypeId] = attr;
  395.                 }
  396.                
  397.                 Attribute[] newAttributes = new Attribute[hash.Values.Count];
  398.                 hash.Values.CopyTo(newAttributes, 0);
  399.                
  400.                 lock (this) {
  401.                     attributes = newAttributes;
  402.                     attributesFiltered = true;
  403.                     attributesFilled = true;
  404.                     metadataVersion = TypeDescriptor.MetadataVersion;
  405.                 }
  406.             }
  407.         }
  408.        
  409.         /// <devdoc>
  410.         /// <para>
  411.         /// Finds the given method through reflection. This method only looks for public methods.
  412.         /// </para>
  413.         /// </devdoc>
  414.         protected static MethodInfo FindMethod(Type componentClass, string name, Type[] args, Type returnType)
  415.         {
  416.             return FindMethod(componentClass, name, args, returnType, true);
  417.         }
  418.        
  419.         /// <devdoc>
  420.         /// <para>
  421.         /// Finds the given method through reflection.
  422.         /// </para>
  423.         /// </devdoc>
  424.         protected static MethodInfo FindMethod(Type componentClass, string name, Type[] args, Type returnType, bool publicOnly)
  425.         {
  426.             MethodInfo result = null;
  427.            
  428.             if (publicOnly) {
  429.                 result = componentClass.GetMethod(name, args);
  430.             }
  431.             else {
  432.                 result = componentClass.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, args, null);
  433.             }
  434.             if (result != null && result.ReturnType != returnType) {
  435.                 result = null;
  436.             }
  437.             return result;
  438.         }
  439.        
  440.         /// <devdoc>
  441.         /// Try to keep this reasonable in sync with Equals(). Specifically,
  442.         /// if A.Equals(B) returns true, A & B should have the same hash code.
  443.         /// </devdoc>
  444.         public override int GetHashCode()
  445.         {
  446.             return nameHash;
  447.         }
  448.        
  449.         /// <devdoc>
  450.         /// This method returns the object that should be used during invocation of members.
  451.         /// Normally the return value will be the same as the instance passed in. If
  452.         /// someone associated another object with this instance, or if the instance is a
  453.         /// custom type descriptor, GetInvocationTarget may return a different value.
  454.         /// </devdoc>
  455.         protected virtual object GetInvocationTarget(Type type, object instance)
  456.         {
  457.            
  458.             if (type == null) {
  459.                 throw new ArgumentNullException("type");
  460.             }
  461.            
  462.             if (instance == null) {
  463.                 throw new ArgumentNullException("instance");
  464.             }
  465.            
  466.             return TypeDescriptor.GetAssociation(type, instance);
  467.         }
  468.        
  469.         /// <devdoc>
  470.         /// <para>
  471.         /// Gets a component site
  472.         /// for the given component.
  473.         /// </para>
  474.         /// </devdoc>
  475.         protected static ISite GetSite(object component)
  476.         {
  477.             if (!(component is IComponent)) {
  478.                 return null;
  479.             }
  480.            
  481.             return ((IComponent)component).Site;
  482.         }
  483.        
  484.         /// <devdoc>
  485.         /// <para>
  486.         /// Gets
  487.         /// the component
  488.         /// that a method should be invoked on.
  489.         /// </para>
  490.         /// </devdoc>
  491.         [Obsolete("This method has been deprecated. Use GetInvocationTarget instead. http://go.microsoft.com/fwlink/?linkid=14202")]
  492.         protected static object GetInvokee(Type componentClass, object component)
  493.         {
  494.            
  495.             if (componentClass == null) {
  496.                 throw new ArgumentNullException("componentClass");
  497.             }
  498.            
  499.             if (component == null) {
  500.                 throw new ArgumentNullException("component");
  501.             }
  502.            
  503.             return TypeDescriptor.GetAssociation(componentClass, component);
  504.         }
  505.     }
  506. }

Developer Fusion