Instance substitution occurs when you want to create one type, but the type that is actually created is different from what you requested. Instance substitution is accomplished when you replace all calls to new with calls to the CreateInstance method. This method searches internal tables within TypeDescriptor for a TypeDescriptionProvider object that is associated with the given data type. If it finds one, it delegates the call to that object.
There are a few cases in the .NET Framework object model where the type of a property is purposely made to be non-specific. For example, the DataSource property on the DataGridView class is typed as object. This design permits the data source to accept several kinds of input, but it provides no common place to add metadata to describe the characteristics of the property. Each data-source property throughout the .NET Framework needs to have identical metadata for type converters and user interface (UI) type editors.
The AttributeProviderAttribute class addresses this situation. When this attribute is placed on a property, the rules change for obtaining attributes for the property descriptor's Attributes collection. Usually, the property descriptor gathers local attributes and merges them with attributes from the property type. When the AttributeProviderAttribute attribute is applied, the attributes are taken from the type returned from AttributeProviderAttribute, not from the actual property type. The AttributeProviderAttribute is used on data sources to point the data source’s specific type to IListSource, and the appropriate metadata is placed on IListSource to enable data binding. This redirection allows external parties such as Visual Studio to easily add metadata to all data sources.
Attributes obtained from a type declared in the AttributeProviderAttribute have a priority between the attributes of the property’s type and the attributes on the property. The full set of attributes available is the merger, in priority order, as shown in the following list:
Property Attributes
Attribute Provider Attributes
Property Type Attributes
Target substitution occurs when one object stands in for another. A common application of target substitution is in the implementation of designers.
In the .NET Framework designer architecture, a component can have a designer associated with it. This designer can implement IDesignerFilter and provide its own properties. These properties are merged into the property set for the component with which the designer is associated. These properties can be new to the component. They can also have the same name and type as properties already defined on the component. When the new property shares the name and type as an existing property, it is called shadowing, because the designer hides, or shadows, the existing property on the component. The following illustration shows the shadowing of a property.
.gif)
Here, the component offers two properties, and the designer also offers two properties. The Text property is offered on both the designer and the component, and is being shadowed. The final result of a call to GetProperties is three properties. One exists on the component, and the other two exist on the designer.
This property filtering is accomplished through the use of ITypeDescriptorFilterService, which the design surface implements. TypeDescriptor capabilities are required when it is time to set a value on the property. The code to set a value on the Grid property would look like this:
gridProp.SetValue(component, value);
The actual type information about the property points it to an instance of the designer, not the component. If a reflection call were made to actually set the property, the call would raise a target invocation exception because the component instance does not match the designer type.
The TypeDescriptor class has inherent logic to work around this situation. When a property call is made, the TypeDescriptor class checks to see if the member type is an instance of the object passed. If so, it lets the call proceed. If not, the class tries to locate the designer for the object, and if the designer can be found and is of the correct type, the class replaces the component instance with the designer instance.
The following methods on TypeDescriptor support target substitution:
The GetExtendedTypeDescriptor method returns an extended custom type descriptor for the given object. An extended type descriptor is a custom type descriptor that offers properties that other objects have added to this object but are not actually defined on the object. For example, in the .NET Framework component model, objects that implement the IExtenderProvider interface can attach properties to other objects that reside in the same IContainer. The GetTypeDescriptor method does not return a type descriptor that provides these extra extended properties, but GetExtendedTypeDescriptor returns the set of these extended properties. The TypeDescriptor class automatically merges the results of these two property collections.
Note: |
|---|
Although the .NET Framework component model only supports extended properties, GetExtendedTypeDescriptor can be used for extended attributes and events as well, if the type description provider supports it. |