Running with Code

Like scissors, only more dangerous

  Home  |   Contact  |   Syndication    |   Login
  67 Posts | 0 Stories | 84 Comments | 22 Trackbacks

News



Archives

Post Categories

All Terralever

ASP.NET

Misc

C# 2.0 introduced a great new feature to the .NET Type system: generics.  Generics are really cool in that they allow you to define template classes; I can use a single class definition to provide a strongly typed collection, for example.  They enable some other tricks that I would tend to consider something of a "hack" as well; for example, this expression evaluates to true:

   1:  typeof(IEnumerable<int>) != typeof(IEnumerable<double>)

This expression is nice because there are some odd class design decisions in places like the PropertyGrid's type structure.  For example, in order to add a PropertyTab to the list of the PropertyGrid's tabs, you need to add a Type to the PropertyTabCollection exposed by the PropertyGrid's PropertyTabs property.  The PropertyGrid caches the tabs that it creates, and so you can't add a single Type to create two property tabs.  Consequently, even if you override the CreateTab method, you can't expect to add two tabs with the same Type.

My solution, then, was to create ExtensionPropertyTab<T>.  This class's type parameter is utterly useless; I create an arbitrary Type using Reflection Emit, close my ExtensionPropertyTab generic type definition with it, and then add the PropertyTab with that closed type.  Works great!  This stuff will be in an upcoming blog post about my PropertyGridEx project.

All of that is leading up to my next hack and, ultimately, my wishlist item #1 for C# 4.0.

There's a simple design-time class called EnumConverter.  This class is the default type converter for all enumeration types; EnumConverter is what displays the Enum names in the property grid when you're choosing items.  I'm creating a type surrogate class that allows you to customize the names of properties, and I've also been working on displaying better values for enumerations.  To this end, I created the EnumTypeConverter<T> class - this class provides enumeration names, but also retrieves friendly names from attributes on each enum entry.  Using generics, I'm able to cache the friendly names so that reflection only needs to be invoked once; System.Enum does something similar.

What I'd like to do, however, is say this:

   1:  public class EnumTypeConverter<T> : TypeConverter where T : enum

C# doesn't allow me to do this.  I get two errors:

error CS1031: Type expected
error CS1001: Identifier expected

So I try using the type name instead:

   1:  public class EnumTypeConverter<T> : TypeConverter where T : Enum

C# doesn't like this either:

error CS0702: Constraint cannot be special class 'System.Enum'

Why?  I get the same error with System.ValueType, even though ultimately it means the same thing as "struct" (though I could understand this difference).  But I can't do this with System.Delegate either (how about calling Invoke() or BeginInvoke() on T?).

Being able to specify Enum as a base would allow me to:

  • Explicitly cast between T and integral numeric types.
  • Specify 0 as the default value of T rather than using default(T).
  • Perform bitwise operations on them

There's really no reason to have a constraint like "Constraint cannot be special class 'System.Enum'."  Let's eliminate this artificial barrier - there shouldn't be any changes needed to be made to the CLR.

posted on Tuesday, January 15, 2008 9:34 AM

Feedback

# re: My C# 4.0 Wishlist, Part 1 : Eliminate Type Constraint Constraints 2/16/2008 7:31 PM Tergiver
I second that wish!

# re: My C# 4.0 Wishlist, Part 1 : Eliminate Type Constraint Constraints 6/5/2008 4:24 PM Thomas Holloway
I know! I ran into that issue today. I also wish that you could do write an extension to a class that will enable implicit casting. If I had either one of these options then I would never have to cast an enum to a byte and a byte to an enum ever again! :)

# re: My C# 4.0 Wishlist, Part 1 : Eliminate Type Constraint Constraints 8/25/2008 7:39 PM BlindWanderer
You can get around this but there is a VS bug that mitigates it if you use it with extension methods. The restriction is a C# limit and not an IL limit, so you compile to IL or decompile to IL, change the type and recompile.

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=351413

Post Feedback

Title:
Name:
Email: (never displayed)
Url:
Comments: 
Please add 1 and 8 and type the answer here: