Background and motivation
All of System.ComponentModel.TypeDescriptor's entry points are currently static and currently lean on either Type or object parameters (e.g., GetConverter(Type), GetEditor(Type, Type), GetAttributes(Type)), which callers often use by passing typeof(<>) and casting return types. But design precedent in .NET has consistently guided development towards generic overloads to improve ergonomics, safety, and analyzability when the type argument is known:
- IServiceProvider usage is universally guided toward GetService() / GetRequiredService() extension methods rather than the non-generic GetService(Type).
- ActivatorUtilities.CreateInstance(…) complements the non-generic factory methods for DI-activated construction.
- Roslyn rule CA2263 – Prefer generic overload when type is known encodes this guidance to reduce boxing/casting and improve clarity. Adding TypeDescriptor generics would align with this rule.
API Proposal
namespace System.ComponentModel
{
public sealed class TypeDescriptor
{
public static TypeDescriptionProvider AddAttributes<T>(params Attribute[] attributes);
public static TypeDescriptionProvider AddAttributes<T>(T instance, params Attribute[] attributes);
public static void AddEditorTable<T>(Hashtable table);
public static void AddProvider<T>(TypeDescriptionProvider provider, T instance);
public static void AddProvider<T>(TypeDescriptionProvider provider);
public static void AddProviderTransparent<T>(TypeDescriptionProvider provider, T instance);
public static void AddProviderTransparent<T>(TypeDescriptionProvider provider);
public static EventDescriptor CreateEvent<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] CT, T>(string name, params Attribute[] attributes);
public static EventDescriptor CreateEvent<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] CT>(EventDescriptor oldEventDescriptor, params Attribute[] attributes);
public static T? CreateInstance<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
IServiceProvider? provider,
Type[]? argTypes,
object?[]? args);
}
}
and so on...
API Usage
Usages of some of the APIs such as:
TypeDescriptor.AddProvider(myProvider, typeof(T));
T? instance = (T?)TypeDescriptor.CreateInstance(myProvider, typeof(T), [], []);
would become
TypeDescriptor.AddProvider<T>(myProvider);
T? instance = TypeDescriptor.CreateInstance<T>(myProvider, [], []);
Alternative Designs
No response
Risks
Generic overload signatures might imply more trim compatibility than actually present.
Background and motivation
All of System.ComponentModel.TypeDescriptor's entry points are currently static and currently lean on either Type or object parameters (e.g., GetConverter(Type), GetEditor(Type, Type), GetAttributes(Type)), which callers often use by passing typeof(<>) and casting return types. But design precedent in .NET has consistently guided development towards generic overloads to improve ergonomics, safety, and analyzability when the type argument is known:
API Proposal
and so on...
API Usage
Usages of some of the APIs such as:
would become
Alternative Designs
No response
Risks
Generic overload signatures might imply more trim compatibility than actually present.