Search code examples
c#winformsicustomtypedescriptor

ICustomTypeDescriptor GetConverter implementation


I have a base class decorated with a TypeDescriptionProviderAttribute that points at a custom implementation of ICustomTypeDescriptor.

There is a derived class that is decorated with a TypeConverterAttribute to do custom type conversion.

BaseClassTypeDescriptor implements ICustomTypeDescriptor.GetConverter by calling the static TypeDescriptor.GetConverter method. That method takes two arguments: the type in question (which I have a reference to), and a flag that indicates whether or not to allow the custom behavior to be called. This has to be set to true to prevent an infinite loop.

A stripped-down version of the code looks like this:

[TypeDescriptionProvider(typeof(BaseClassTypeDescriptionProvider))]
public class BaseClass
{
    public class BaseClassTypeDescriptionProvider : TypeDescriptionProvider
    {
        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType_, object instance_)
        {
            return new BaseClassTypeDescriptor(objectType_);
        }
    }

    public class BaseClassTypeDescriptor : ICustomTypeDescriptor 
    {
         private Type _type;

         public BaseClassTypeDescriptor(Type type_)
         {
             _type = type_;
         }

         TypeConverter ICustomTypeDescriptor.GetConverter()
         {
             return TypeDescriptor.GetConverter(_type, true);
         }
    }
}

[TypeConverter(typeof(MyTypeConverter))]
public class DerivedClass : BaseClass
{
}

The problem is that this flag seems to not only bypass BaseClassTypeDescriptor, but also seems to prevent .NET from recognizing the TypeConverterAttribute on the derived class.

I've worked around this by reimplementing the check for a TypeConverterAttribute inside my implementation of MyCustomTypeConverter.GetConverter, like so:

TypeConverter ICustomTypeDescriptor.GetConverter()
{
    object[] typeConverterAttributeArray = _type.GetCustomAttributes(typeof(TypeConverterAttribute), true);
    if (typeConverterAttributeArray.Length == 1)
    {
        TypeConverterAttribute a = (TypeConverterAttribute)typeConverterAttributeArray[0];
        Type converterType = MyTypeLoader.GetType(a.ConverterTypeName);
        return (TypeConverter)Activator.CreateInstance(converterType);
    }
    else
    {
        return TypeDescriptor.GetConverter(_type, true);
    }
}

This is far from an ideal solution. Any suggestion as to how I can delegate that responsibility back where it belongs?


Solution

  • In your example, the overload of TypeDescriptor.GetConverter(object component, bool noCustomTypeDesc) seems to return the TypeDescriptor for the Type type, since it expects an instance.

    I tried your example with

    return TypeDescriptor.GetConverter(Activator.CreateInstance(_type), true);
    

    And got the infinite loop the bool value was supposed to prevent.

    I don't know why this works this way, and whether this is documented somehow, but I bet they don't expect a TypeDescriptionProvider to call TypeDescriptor.GetConverter() at all.