2016-08-03 10:59:49 +00:00
//------------------------------------------------------------------------------
// <copyright file="PropertyDescriptor.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/ *
* /
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2113:SecureLateBindingMethods", Scope="member", Target="System.ComponentModel.PropertyDescriptor.GetTypeFromName(System.String):System.Type")]
namespace System.ComponentModel {
using Microsoft.Win32 ;
using System ;
using System.Collections ;
using System.ComponentModel.Design ;
using System.Diagnostics ;
using System.Reflection ;
using System.Runtime.InteropServices ;
using System.Runtime.Remoting.Activation ;
using System.Runtime.Serialization.Formatters ;
using System.Security ;
using System.Security.Permissions ;
/// <devdoc>
/// <para>Provides a description of a property.</para>
/// </devdoc>
[HostProtection(SharedState = true)]
[System.Runtime.InteropServices.ComVisible(true)]
public abstract class PropertyDescriptor : MemberDescriptor {
private TypeConverter converter = null ;
private Hashtable valueChangedHandlers ;
private object [ ] editors ;
private Type [ ] editorTypes ;
private int editorCount ;
/// <devdoc>
/// <para>
/// Initializes a new instance of the <see cref='System.ComponentModel.PropertyDescriptor'/> class with the specified name and
/// attributes.
/// </para>
/// </devdoc>
protected PropertyDescriptor ( string name , Attribute [ ] attrs )
: base ( name , attrs ) {
}
/// <devdoc>
/// <para>
/// Initializes a new instance of the <see cref='System.ComponentModel.PropertyDescriptor'/> class with
/// the name and attributes in the specified <see cref='System.ComponentModel.MemberDescriptor'/>.
/// </para>
/// </devdoc>
protected PropertyDescriptor ( MemberDescriptor descr )
: base ( descr ) {
}
/// <devdoc>
/// <para>
/// Initializes a new instance of the <see cref='System.ComponentModel.PropertyDescriptor'/> class with
/// the name in the specified <see cref='System.ComponentModel.MemberDescriptor'/> and the
/// attributes in both the <see cref='System.ComponentModel.MemberDescriptor'/> and the
/// <see cref='System.Attribute'/> array.
/// </para>
/// </devdoc>
protected PropertyDescriptor ( MemberDescriptor descr , Attribute [ ] attrs )
: base ( descr , attrs ) {
}
/// <devdoc>
/// <para>
/// When overridden in a derived class, gets the type of the
/// component this property
/// is bound to.
/// </para>
/// </devdoc>
public abstract Type ComponentType { get ; }
/// <devdoc>
/// <para>
/// Gets the type converter for this property.
/// </para>
/// </devdoc>
public virtual TypeConverter Converter {
get {
// Always grab the attribute collection first here, because if the metadata version
// changes it will invalidate our type converter cache.
AttributeCollection attrs = Attributes ;
if ( converter = = null ) {
TypeConverterAttribute attr = ( TypeConverterAttribute ) attrs [ typeof ( TypeConverterAttribute ) ] ;
if ( attr . ConverterTypeName ! = null & & attr . ConverterTypeName . Length > 0 ) {
Type converterType = GetTypeFromName ( attr . ConverterTypeName ) ;
if ( converterType ! = null & & typeof ( TypeConverter ) . IsAssignableFrom ( converterType ) )
{
converter = ( TypeConverter ) CreateInstance ( converterType ) ;
}
}
if ( converter = = null ) {
converter = TypeDescriptor . GetConverter ( PropertyType ) ;
}
}
return converter ;
}
}
/// <devdoc>
/// <para>
/// Gets a value
/// indicating whether this property should be localized, as
/// specified in the <see cref='System.ComponentModel.LocalizableAttribute'/>.
/// </para>
/// </devdoc>
public virtual bool IsLocalizable {
get {
return ( LocalizableAttribute . Yes . Equals ( Attributes [ typeof ( LocalizableAttribute ) ] ) ) ;
}
}
/// <devdoc>
/// <para>
/// When overridden in
/// a derived class, gets a value
/// indicating whether this property is read-only.
/// </para>
/// </devdoc>
public abstract bool IsReadOnly { get ; }
/// <devdoc>
/// <para>
/// Gets a value
/// indicating whether this property should be serialized as specified in the <see cref='System.ComponentModel.DesignerSerializationVisibilityAttribute'/>.
/// </para>
/// </devdoc>
public DesignerSerializationVisibility SerializationVisibility {
get {
DesignerSerializationVisibilityAttribute attr = ( DesignerSerializationVisibilityAttribute ) Attributes [ typeof ( DesignerSerializationVisibilityAttribute ) ] ;
return attr . Visibility ;
}
}
/// <devdoc>
/// <para>
/// When overridden in a derived class,
/// gets the type of the property.
/// </para>
/// </devdoc>
public abstract Type PropertyType { get ; }
/// <devdoc>
/// Allows interested objects to be notified when this property changes.
/// </devdoc>
public virtual void AddValueChanged ( object component , EventHandler handler ) {
if ( component = = null ) throw new ArgumentNullException ( "component" ) ;
if ( handler = = null ) throw new ArgumentNullException ( "handler" ) ;
if ( valueChangedHandlers = = null ) {
valueChangedHandlers = new Hashtable ( ) ;
}
EventHandler h = ( EventHandler ) valueChangedHandlers [ component ] ;
valueChangedHandlers [ component ] = Delegate . Combine ( h , handler ) ;
}
/// <devdoc>
/// <para>
/// When overridden in a derived class, indicates whether
/// resetting the <paramref name="component "/>will change the value of the
/// <paramref name="component"/>.
/// </para>
/// </devdoc>
public abstract bool CanResetValue ( object component ) ;
/// <devdoc>
/// <para>
/// Compares this to another <see cref='System.ComponentModel.PropertyDescriptor'/>
/// to see if they are equivalent.
/// NOTE: If you make a change here, you likely need to change GetHashCode() as well.
/// </para>
/// </devdoc>
public override bool Equals ( object obj ) {
try {
if ( obj = = this ) {
return true ;
}
if ( obj = = null ) {
return false ;
}
// Assume that 90% of the time we will only do a .Equals(...) for
// propertydescriptor vs. propertydescriptor... avoid the overhead
// of an instanceof call.
PropertyDescriptor pd = obj as PropertyDescriptor ;
if ( pd ! = null & & pd . NameHashCode = = this . NameHashCode
& & pd . PropertyType = = this . PropertyType
& & pd . Name . Equals ( this . Name ) ) {
return true ;
}
}
catch { }
return false ;
}
/// <devdoc>
/// <para>
/// Creates an instance of the
/// specified type.
/// </para>
/// </devdoc>
protected object CreateInstance ( Type type ) {
Type [ ] typeArgs = new Type [ ] { typeof ( Type ) } ;
ConstructorInfo ctor = type . GetConstructor ( typeArgs ) ;
if ( ctor ! = null ) {
return TypeDescriptor . CreateInstance ( null , type , typeArgs , new object [ ] { PropertyType } ) ;
}
return TypeDescriptor . CreateInstance ( null , type , null , null ) ;
}
/// <devdoc>
/// In an inheriting class, adds the attributes of the inheriting class to the
/// specified list of attributes in the parent class. For duplicate attributes,
/// the last one added to the list will be kept.
/// </devdoc>
protected override void FillAttributes ( IList attributeList ) {
// Each time we fill our attributes, we should clear our cached
// stuff.
converter = null ;
editors = null ;
editorTypes = null ;
editorCount = 0 ;
base . FillAttributes ( attributeList ) ;
}
/// <include file='doc\PropertyDescriptor.uex' path='docs/doc[@for="PropertyDescriptor.GetChildProperties"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public PropertyDescriptorCollection GetChildProperties ( ) {
return GetChildProperties ( null , null ) ;
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public PropertyDescriptorCollection GetChildProperties ( Attribute [ ] filter ) {
return GetChildProperties ( null , filter ) ;
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public PropertyDescriptorCollection GetChildProperties ( object instance ) {
return GetChildProperties ( instance , null ) ;
}
/// <devdoc>
/// Retrieves the properties
/// </devdoc>
public virtual PropertyDescriptorCollection GetChildProperties ( object instance , Attribute [ ] filter ) {
if ( instance = = null ) {
return TypeDescriptor . GetProperties ( PropertyType , filter ) ;
}
else {
return TypeDescriptor . GetProperties ( instance , filter ) ;
}
}
/// <devdoc>
/// <para>
/// Gets an editor of the specified type.
/// </para>
/// </devdoc>
public virtual object GetEditor ( Type editorBaseType ) {
object editor = null ;
// Always grab the attribute collection first here, because if the metadata version
// changes it will invalidate our editor cache.
AttributeCollection attrs = Attributes ;
// Check the editors we've already created for this type.
//
if ( editorTypes ! = null ) {
for ( int i = 0 ; i < editorCount ; i + + ) {
if ( editorTypes [ i ] = = editorBaseType ) {
return editors [ i ] ;
}
}
}
// If one wasn't found, then we must go through the attributes.
//
if ( editor = = null ) {
for ( int i = 0 ; i < attrs . Count ; i + + ) {
EditorAttribute attr = attrs [ i ] as EditorAttribute ;
if ( attr = = null ) {
continue ;
}
Type editorType = GetTypeFromName ( attr . EditorBaseTypeName ) ;
if ( editorBaseType = = editorType ) {
Type type = GetTypeFromName ( attr . EditorTypeName ) ;
if ( type ! = null ) {
editor = CreateInstance ( type ) ;
break ;
}
}
}
// Now, if we failed to find it in our own attributes, go to the
// component descriptor.
//
if ( editor = = null ) {
editor = TypeDescriptor . GetEditor ( PropertyType , editorBaseType ) ;
}
// Now, another slot in our editor cache for next time
//
if ( editorTypes = = null ) {
editorTypes = new Type [ 5 ] ;
editors = new object [ 5 ] ;
}
if ( editorCount > = editorTypes . Length ) {
Type [ ] newTypes = new Type [ editorTypes . Length * 2 ] ;
object [ ] newEditors = new object [ editors . Length * 2 ] ;
Array . Copy ( editorTypes , newTypes , editorTypes . Length ) ;
Array . Copy ( editors , newEditors , editors . Length ) ;
editorTypes = newTypes ;
editors = newEditors ;
}
editorTypes [ editorCount ] = editorBaseType ;
editors [ editorCount + + ] = editor ;
}
return editor ;
}
/// <devdoc>
2017-08-21 15:34:15 +00:00
/// Try to keep this reasonable in sync with Equals(). Specifically,
2016-08-03 10:59:49 +00:00
/// if A.Equals(B) returns true, A & B should have the same hash code.
/// </devdoc>
public override int GetHashCode ( ) {
return this . NameHashCode ^ PropertyType . GetHashCode ( ) ;
}
/// <devdoc>
/// This method returns the object that should be used during invocation of members.
/// Normally the return value will be the same as the instance passed in. If
/// someone associated another object with this instance, or if the instance is a
/// custom type descriptor, GetInvocationTarget may return a different value.
/// </devdoc>
protected override object GetInvocationTarget ( Type type , object instance ) {
object target = base . GetInvocationTarget ( type , instance ) ;
ICustomTypeDescriptor td = target as ICustomTypeDescriptor ;
if ( td ! = null ) {
target = td . GetPropertyOwner ( this ) ;
}
return target ;
}
/// <devdoc>
/// <para>Gets a type using its name.</para>
/// </devdoc>
protected Type GetTypeFromName ( string typeName ) {
if ( typeName = = null | | typeName . Length = = 0 ) {
return null ;
}
// try the generic method.
Type typeFromGetType = Type . GetType ( typeName ) ;
// If we didn't get a type from the generic method, or if the assembly we found the type
// in is the same as our Component's assembly, use or Component's assembly instead. This is
// because the CLR may have cached an older version if the assembly's version number didn't change
// See VSWhidbey 560732
Type typeFromComponent = null ;
if ( ComponentType ! = null ) {
if ( ( typeFromGetType = = null ) | |
( ComponentType . Assembly . FullName . Equals ( typeFromGetType . Assembly . FullName ) ) ) {
int comma = typeName . IndexOf ( ',' ) ;
if ( comma ! = - 1 )
typeName = typeName . Substring ( 0 , comma ) ;
typeFromComponent = ComponentType . Assembly . GetType ( typeName ) ;
}
}
return typeFromComponent ? ? typeFromGetType ;
}
/// <devdoc>
/// <para>
/// When overridden in a derived class, gets the current
/// value
/// of the
/// property on a component.
/// </para>
/// </devdoc>
public abstract object GetValue ( object component ) ;
/// <devdoc>
/// This should be called by your property descriptor implementation
/// when the property value has changed.
/// </devdoc>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
protected virtual void OnValueChanged ( object component , EventArgs e ) {
if ( component ! = null & & valueChangedHandlers ! = null ) {
EventHandler handler = ( EventHandler ) valueChangedHandlers [ component ] ;
if ( handler ! = null ) {
handler ( component , e ) ;
}
}
}
/// <devdoc>
/// Allows interested objects to be notified when this property changes.
/// </devdoc>
public virtual void RemoveValueChanged ( object component , EventHandler handler ) {
if ( component = = null ) throw new ArgumentNullException ( "component" ) ;
if ( handler = = null ) throw new ArgumentNullException ( "handler" ) ;
if ( valueChangedHandlers ! = null ) {
EventHandler h = ( EventHandler ) valueChangedHandlers [ component ] ;
h = ( EventHandler ) Delegate . Remove ( h , handler ) ;
if ( h ! = null ) {
valueChangedHandlers [ component ] = h ;
}
else {
valueChangedHandlers . Remove ( component ) ;
}
}
}
/// <devdoc>
/// Return current set of ValueChanged event handlers for a specific
/// component, in the form of a combined multicast event handler.
/// Returns null if no event handlers currently assigned to component.
/// </devdoc>
internal protected EventHandler GetValueChangedHandler ( object component ) {
if ( component ! = null & & valueChangedHandlers ! = null ) {
return ( EventHandler ) valueChangedHandlers [ component ] ;
}
else {
return null ;
}
}
/// <devdoc>
/// <para>
/// When overridden in a derived class, resets the
/// value
/// for this property
/// of the component.
/// </para>
/// </devdoc>
public abstract void ResetValue ( object component ) ;
/// <devdoc>
/// <para>
/// When overridden in a derived class, sets the value of
/// the component to a different value.
/// </para>
/// </devdoc>
public abstract void SetValue ( object component , object value ) ;
/// <devdoc>
/// <para>
/// When overridden in a derived class, indicates whether the
/// value of
/// this property needs to be persisted.
/// </para>
/// </devdoc>
public abstract bool ShouldSerializeValue ( object component ) ;
/// <devdoc>
/// Indicates whether value change notifications for this property may originate from outside the property
/// descriptor, such as from the component itself (value=true), or whether notifications will only originate
/// from direct calls made to PropertyDescriptor.SetValue (value=false). For example, the component may
/// implement the INotifyPropertyChanged interface, or may have an explicit '{name}Changed' event for this property.
/// </devdoc>
public virtual bool SupportsChangeEvents {
get {
return false ;
}
}
}
}