How can I avoid having a separate custom TypeDescriptorProvider for each of my classes?

1.8k views Asked by At

I've added functionality to my project that allows the users to add their own custom properties to objects. I've created my own custom TypeDescriptor, PropertyDescriptor and TypeDescriptorProviders etc.. etc.. to do this.

Here's my problem. Right now I have it all working, but had to create a separate TypeDescriptionProvider for each object object type that can have the custom properties. Here's what my TypeDescriptionProviders look like

//type AClass Custom Provider
class AClassTypeProvider : TypeDescriptionProvider
{
    private static TypeDescriptionProvider defaultTypeProvider = TypeDescriptor.GetProvider(typeof(AClass));

    public AClassTypeProvider (): base(defaultTypeProvider)
    {

    }

    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
    {
        ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);

        //returns a custom type descriptor based on a UserPropertyHostType enum value, and the default descriptor
        return new InfCustomTypeDescriptor(UserPropertyHostType.SiteRegion, defaultDescriptor);
    }
}


//type BClass Custom Provider
class BClassTypeProvider : TypeDescriptionProvider
{
    private static TypeDescriptionProvider defaultTypeProvider =   TypeDescriptor.GetProvider(typeof(BClass));

    public BClassTypeProvider (): base(defaultTypeProvider)
    {

    }

    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
    {
        ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);

        //returns a custom type descriptor based on a UserPropertyHostType enum value, and the default descriptor
        return new InfCustomTypeDescriptor(UserPropertyHostType.Building, defaultDescriptor);
    }
}

So each of my custom TypeDescriptionProviders calls the base(TypeDescriptionProvider parent) base constructor by passing it the default TypeDescriptionProvider of a specific type.

The GetTypeDescriptor() method calls base.GetTypeDescriptor() to get the default descriptor which is then used by my custom type descriptor to add on the custom properties.

Is there some way to combine these into a single generic custom TypeDescriptionProvider that has the same functionality, but is not tied to a specific type? Can I skip providing the parent TypeDescriptionProvider in the constructor but later set it in the GetTypeDescriptor() method when I know specifically what type of object is being queried? Or is there some other way of getting the default descriptor of a type other then calling the base.GetTypeDescriptor(Type t,object ins) method?

2

There are 2 answers

0
Thomas Levesque On

This generic class should do what you want :

class CustomTypeProvider<T> : TypeDescriptionProvider
{
    private static TypeDescriptionProvider defaultTypeProvider = TypeDescriptor.GetProvider(typeof(T));

    public CustomTypeProvider(): base(defaultTypeProvider)
    {

    }

    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
    {
        ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);

        //returns a custom type descriptor based on a UserPropertyHostType enum value, and the default descriptor
        return new InfCustomTypeDescriptor(UserPropertyHostType.SiteRegion, defaultDescriptor);
    }
}
1
itowlson On

I have handled this in the past by using a generic type:

public class MyTypeDescriptionProvider<T> : TypeDescriptionProvider
{
  public MyTypeDescriptionProvider()
    : base(TypeDescriptor.GetProvider(typeof(T)))
  {
  }
}

I am pretty sure you could handle it similarly in a non-generic type by passing the type as a constructor parameter:

public class MyTypeDescriptionProvider : TypeDescriptionProvider
{
  public MyTypeDescriptionProvider(Type t)
    : base(TypeDescriptor.GetProvider(t))
  {
  }
}

This is probably preferable if you don't need to use the type within the provider -- haven't tested it though.

Then when using this provider, classes are registered along the lines of:

TypeDescriptor.AddProvider(new MyTypeDescriptionProvider<ClassA>(), typeof(ClassA));
TypeDescriptor.AddProvider(new MyTypeDescriptionProvider<ClassB>(), typeof(ClassB));

etc.