Sei sulla pagina 1di 9

Using a TypeDescriptionProvider to support dynamic run-time properties...

1 de 9

http://www.codeproject.com/Articles/26992/Using-a-TypeDescriptionPr...

Articles Languages C# How To

Using a TypeDescriptionProvider to support


dynamic run-time properties
Nish Nishant, 16 Jun 2008

CPOL

5.00 (40 votes)


This articles explains how to implement a TypeDescriptionProvider for a class to support multiple
object types using a single class type

Download sample project (VS 2008) - 13.6 KB

14/09/2016 11:40

Using a TypeDescriptionProvider to support dynamic run-time properties...

2 de 9

http://www.codeproject.com/Articles/26992/Using-a-TypeDescriptionPr...

Introduction
Recently at work, I had to use the TypeDescriptionProvider attribute while prototyping
some new features for our product, and I thought it would be a good idea to demonstrate how to use
this attribute and its related classes. In this article, I will go through a sample demo application which
consists of a list of objects and a property grid that shows the properties for the selected object. For
the demo, I assume that there will always be two types of objects - one that represents a book and the
other that represents a movie. The only common property across the two objects is the Name
property. This is what my Book object would look like:
Name

The title of the book

Amazon Rank

Its sales rank on Amazon

Author

The author of the book

HardCover

Whether it's available in hard-cover

And, here's what my Movie object would look like:


Name

The name of the movie

Director

The director of the movie

Duration

Duration of the movie

14/09/2016 11:40

Using a TypeDescriptionProvider to support dynamic run-time properties...

3 de 9

Rating

The movie rating

Release Date

When it was released

http://www.codeproject.com/Articles/26992/Using-a-TypeDescriptionPr...

One way of designing for this scenario would be to have a base class (with just the Name property)
and two derived classes - one for Book and one for Movie. But, consider the following two extra
requirements:
New object types may be added at any time
New properties might be added for existing object types at any time (including at run time)
To support this would mean having to add new classes frequently and also to modify the existing
classes. And, that still won't address dynamic adding of properties to an existing object. This is where
using a TypeDescriptionProvider turns out to be very useful, and the rest of the article will
explain how to implement the requirements using that approach.

Technical Implementation
The first step is to implement an enumeration for the type of object. When we add new object types,
we would add those to this enumeration as and when required.
enum TitleCategory
{
Book,
Movie
}
Now, we will add a single sealed class called Title which will define the type description provider
and also provide for default properties.
[TypeDescriptionProvider(typeof(TitleTypeDescriptionProvider))]
sealed class Title
{
public Title(String name, TitleCategory category)
{
this.Name = name;
this.Category = category;
}
public String Name { get; set; }
[Browsable(false)]
public TitleCategory Category { get; private set; }
public override string ToString()
{
return Name;
}
private Dictionary<String, Object> customFieldValues =
new Dictionary<String, Object>();
public Object this[String fieldName]
{
get
{
Object value = null;
customFieldValues.TryGetValue(fieldName, out value);
return value;
}

14/09/2016 11:40

Using a TypeDescriptionProvider to support dynamic run-time properties...

4 de 9

http://www.codeproject.com/Articles/26992/Using-a-TypeDescriptionPr...

set
{
customFieldValues[fieldName] = value;
}
}
}
In addition to the Name property, I also have a Category property which specifies the type of the
object. In addition, you will see that I also have a dictionary for the custom property values and an
indexer that can be used to get and set custom properties on any object. Also notice the
TypeDescriptionProvider attribute on the class that specifies
TitleTypeDescriptionProvider as the type description provider.
The next thing to do is to add a class to represent a custom property field. All it would need would be
the name of the field and its data type.
Tech Note: In my demo, I do not validate the data for
the data type, but obviously, that would be a mandatory
chore when putting this to practical use. Else, you'd have
mismatching data which would pollute the runtime
object.
class CustomField
{
public CustomField(String name, Type dataType)
{
Name = name;
DataType = dataType;
}
public String Name { get; private set; }
public Type DataType { get; private set; }
}
Now, we can write the TitleTypeDescriptionProvider class:
class TitleTypeDescriptionProvider : TypeDescriptionProvider
{
private static TypeDescriptionProvider defaultTypeProvider =
TypeDescriptor.GetProvider(typeof(Title));
public TitleTypeDescriptionProvider() : base(defaultTypeProvider)
{
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType,
object instance)
{
ICustomTypeDescriptor defaultDescriptor =
base.GetTypeDescriptor(objectType, instance);
return instance == null ? defaultDescriptor :
new TitleCustomTypeDescriptor(defaultDescriptor, instance);
}
}
The important method here is the GetTypeDescriptor override. The default descriptor is
returned when the instance is null, otherwise we return a TitleCustomTypeDescriptor
object. The TitleCustomTypeDescriptor is written as follows:

14/09/2016 11:40

Using a TypeDescriptionProvider to support dynamic run-time properties...

5 de 9

http://www.codeproject.com/Articles/26992/Using-a-TypeDescriptionPr...

class TitleCustomTypeDescriptor : CustomTypeDescriptor


{
public TitleCustomTypeDescriptor(ICustomTypeDescriptor parent, object
instance)
: base(parent)
{
Title title = (Title)instance;

customFields.AddRange(CustomFieldsGenerator.GenerateCustomFields(title.Category)
.Select(f => new
CustomFieldPropertyDescriptor(f)).Cast<PropertyDescriptor>());
}
private List<PropertyDescriptor> customFields = new
List<PropertyDescriptor>();
public override PropertyDescriptorCollection GetProperties()
{
return new PropertyDescriptorCollection(base.GetProperties()
.Cast<PropertyDescriptor>().Union(customFields).ToArray());
}
public override PropertyDescriptorCollection GetProperties(Attribute[]
attributes)
{
return new PropertyDescriptorCollection(base.GetProperties(attributes)
.Cast<PropertyDescriptor>().Union(customFields).ToArray());
}
}
The crux of this class is that we generate a list of custom fields for the object based on the
Category property. Then, in the GetProperties overrides, we add these properties (fields) to
the default list. It's here that the entire dynamic nature of this design is revealed. This allows us to
dynamically add new properties to an object type. For the demo, I have a
CustomFieldsGenerator class that returns the dynamic fields.
internal static IEnumerable<CustomField> GenerateCustomFields(TitleCategory
category)
{
List<CustomField> customFields = new List<CustomField>();
switch(category)
{
case TitleCategory.Book:
customFields.Add(new CustomField("Author", typeof(String)));
customFields.Add(new CustomField("HardCover", typeof(bool)));
customFields.Add(new CustomField("Amazon Rank", typeof(int)));
break;
case TitleCategory.Movie:
customFields.Add(new CustomField("Director", typeof(String)));
customFields.Add(new CustomField("Rating", typeof(MovieRating)));
customFields.Add(new CustomField("Duration", typeof(TimeSpan)));
customFields.Add(new CustomField("Release Date", typeof(DateTime)));
break;
}
return customFields;
}

14/09/2016 11:40

Using a TypeDescriptionProvider to support dynamic run-time properties...

6 de 9

http://www.codeproject.com/Articles/26992/Using-a-TypeDescriptionPr...

And each field is stored using a CustomFieldPropertyDescriptor class which is responsible


for establishing the behavior of the custom properties.
class CustomFieldPropertyDescriptor : PropertyDescriptor
{
public CustomField CustomField { get; private set; }
public CustomFieldPropertyDescriptor(CustomField customField)
: base(customField.Name, new Attribute[0])
{
CustomField = customField;
}
public override bool CanResetValue(object component)
{
return false;
}
public override Type ComponentType
{
get
{
return typeof(Title);
}
}
public override object GetValue(object component)
{
Title title = (Title)component;
return title[CustomField.Name] ?? (CustomField.DataType.IsValueType ?
(Object)Activator.CreateInstance(CustomField.DataType) : null);
}
public override bool IsReadOnly
{
get
{
return false;
}
}
public override Type PropertyType
{
get
{
return CustomField.DataType;
}
}
public override void ResetValue(object component)
{
throw new NotImplementedException();
}
public override void SetValue(object component, object value)
{
Title title = (Title)component;
title[CustomField.Name] = value;
}
public override bool ShouldSerializeValue(object component)
{
return false;
}

14/09/2016 11:40

Using a TypeDescriptionProvider to support dynamic run-time properties...

7 de 9

http://www.codeproject.com/Articles/26992/Using-a-TypeDescriptionPr...

}
The important methods here are the GetValue and SetValue overrides. I use the indexer of the
Title class for both methods. Notice how I also return a default value based on the type of the
object if the dynamic field has not been set on the Title object when the value is requested. Also
see the PropertyType property - this allows us to specify the exact data type for a specific field.
For example, the movie rating is an enumeration of type MovieRating which is respected by the
property grid.
enum MovieRating
{
G,
PG,
PG13,
R,
NC17
}

That's pretty much what's there to it. It's not just the property grid that respects type descriptors, any
control that supports data binding will work just as expected. So, you could pass this to a data grid
view or to a third party data visualization control and it'll all work just fine. Note that in code, you
cannot access the dynamic properties the normal way, instead you'd have to access them via the
indexer as shown below:
Title title = new Title(name, TitleCategory.Movie);
title["Director"] = director;
title["Rating"] = rating;
title["Duration"] = duration;
title["Release Date"] = releaseDate;
Alright, that's it from me. As usual, all sorts of feedback is thanked for in advance.

History
June 14, 2008 - Article first published.

14/09/2016 11:40

Using a TypeDescriptionProvider to support dynamic run-time properties...

8 de 9

http://www.codeproject.com/Articles/26992/Using-a-TypeDescriptionPr...

License
This article, along with any associated source code and files, is licensed under The Code Project Open
License (CPOL)

Share
About the Author
Nish Nishant
United States
Nish Nishant is a Software Architect/Consultant based out of
Columbus, Ohio. He has over 16 years of software industry
experience in various roles including Lead Software
Architect, Principal Software Engineer, and Product
Manager. Nish is a recipient of the annual Microsoft Visual
C++ MVP Award since 2002 (14 consecutive awards as of
2015).
Nish is an industry acknowledged expert in the Microsoft
technology stack. He authored
C++/CLI in Action for Manning Publications in 2005, and had
previously co-authored
Extending MFC Applications with the .NET Framework for
Addison Wesley in 2003. In addition, he has over 140
published technology articles on CodeProject.com and
another 250+ blog articles on his
WordPress blog. Nish is vastly experienced in team
management, mentoring teams, and directing all stages of
software development.
Contact Nish : You can reach Nish on his google email id
voidnish.
Website and Blog
www.voidnish.com
voidnish.wordpress.com

14/09/2016 11:40

Using a TypeDescriptionProvider to support dynamic run-time properties...

9 de 9

http://www.codeproject.com/Articles/26992/Using-a-TypeDescriptionPr...

You may also be interested in...


Dynamic Properties
for PropertyGrid

Pro

Top 5 .NET Metrics,


Tips & Tricks

HyperDescriptor:
Accelerated
dynamic property
access

10 Ways to Boost
COBOL Application
Development

Open Source
Support Report

SAPrefs Netscape-like
Preferences Dialog

Comments and Discussions


15 messages have been posted for this article Visit http://www.codeproject.com/Articles/26992
/Using-a-TypeDescriptionProvider-to-support-dynamic to post and view comments on this article,
or click here to get a print view with messages.

Permalink | Advertise | Privacy | Terms of Use | Mobile


Web02 | 2.8.160904.1 | Last Updated 16 Jun 2008

Selecione o idioma

Article Copyright 2008 by Nish Nishant


Everything else Copyright CodeProject, 1999-2016

14/09/2016 11:40

Potrebbero piacerti anche