views:

207

answers:

2

I'm writing a wrapper for the WinForms ComboBox control that will let me populate the dropdown with a List<T>, and has a Selected property that returns an item of type T (or null if nothing selected).

Rather than having a Selected property, I'd like it to be named based on the generic type automatically. For example:

  • MyDropDownList<User> would have a SelectedUser property
  • MyDropDownList<Department> would have a SelectedDepartment property
  • MyDropDownList<State> would have a SelectedState property

With LINQ, I can create anonymous types during grouping, like so:

var usersByGender = users
    .GroupBy(x => x.Gender)
    .Select(group => new {Gender = group.Key, List = group.ToList()});

Which will result in a list of the generated anonymous type containing a Gender property and List<User> that are detectable by IntelliSense. The question is, can I somehow do this with properties in a generic class?

EDIT: I now realize I'm essentially asking for "method_missing" in C# 3.0, which is probably impossible. I'm open to suggestions, though.

+1  A: 

No, you cannot do that. The whole idea behind generic types is that they apply equally to all types which can be specified in the generic parameter. This wouldn't be the case if every specialization were allowed to declare differently-named members.

jlew
+1  A: 

I don't think you can do it. The only approach that has even a remote chance of working would be to create some kind of factory method that created the type and returned it. Basically your generic type becomes a base class and IL is dynamically written creating a concrete class that inherits from the generic but with the new property added in. Of course the object that is returned would be really anonymous and you'd only be able to access it through reflection since you wouldn't have a type to actually cast to:

public static class CrazyFactory
{
     public static object CreateTypedComboList<T>()
     {
          //magic happens
          return object;
     }
}

Using it would then require

object userCombo = CrazyFactory.CreateTypedComboList<User>();
PropertyInfo selectedUserProperty = userCombo.GetType().GetProperty("SelectedUser");
selectedUserProperty.SetValue(userCombo, user);

Which is hardly a step up from a simple T SelectedItem property.


From a brief look it appears that this type of thing will be easier when c# 4.0 brings us dynamic types. By implementing the IDynamicObject interface it will be possible to catch all calls to undefined properties and handle them so you could use logic like the following:

public override MetaObject GetMember(GetMemberAction action, MetaObject[] args)
{
     //not sure on the real property name here...
     string actionName = action.Name;

     if (actionName = "Selected" + typeof(T).Name)
     {
          return SelectedItem; //in some MetaObject wrapper 
     }
}

I've been following this article and haven't touched dynamics myself yet, but it certainly appears like what you want is possible. I still wouldn't do it though - you won't get Intellisense and it seems like a fragile and complicated method for defining functionality.

Martin Harris