views:

940

answers:

6

I'm not talking about generic classes that declare properties or fields with the type of a generic parameter. I'm talking about generic properties which could be applied to both generic and non-generic classes.

I'm not talking about this:

public class Base<T>
{
    public T BaseProperty { get; set; }
}

I'm talking about this:

public class Base
{
    public T BaseProperty<T>
    {
       get
       {
          // Insert magic
       }
       set
       {
          // Insert magic
       }
    }
}

Or this:

public class Base<U>
{
    public T BaseProperty<T>
    {
       get
       {
          // Insert magic
       }
       set
       {
          // Insert magic
       }
    }

    public U OtherBaseProperty { get; set; }
}

The usage would go something like this:

var b = new Base();
b.BaseProperty<int> = 42;
int i = b.BaseProperty<int>;
b.BaseProperty<string> = "Hi";
string s = b.BaseProperty<string>;

Or for the second example:

var b = new Base<string>();
b.BaseProperty<int> = 42;
int i = b.BaseProperty<int>;
b.OtherBaseProperty = "Hi";
string s = b.OtherBaseProperty;

The // Insert Magic refers to handling each call to the generic property getter or setter that has a different type for the type parameter.

For example this:

b.BaseProperty<int> = 42;

Needs to be handled differently to:

b.BaseProperty<string> = "Hi";

I would envisage that for each type T if the getter is called before the setter is called then default(T) is returned. When the setter is called the value is stored per type T so that when the getter is subsequently called the previous value that was set for that type is returned.

Note that under the covers properties are just methods.

Do you think this would be useful?

+1  A: 

No .

tsilb
+1  A: 

Without a killer use case, no. You can already achieve the same thing with a pair of generic methods, should you need it.

Daniel Earwicker
A: 

If for some bizarre reason you decided you wanted it, you could sort of fake it with methods:

public class Thing
{
    Dictionary<Type, object> xDict = new Dictionary<Type,object>();
    public void set_X<T>(T x)
    {
        xDict[typeof(T)] = x;
    }
    public T get_X<T>()
    {
        return (T)xDict[typeof(T)];
    }
}

Why you would want to is an entirely different matter, though. It generally makes more sense to start with something you want to do than some way you want to do it.

Khoth
+8  A: 

I've had a couple of times where I would have liked the ability to do this, yes.

However, the syntax involved would be pretty ugly, and it's sufficiently rarely useful that I think I prefer to just suck it up and go with generic methods.

Jon Skeet
Indeed, there's been once or twice when it would have been handy. I asked Mads Torgersen @ MS about this once and he basically said, "Why would you wanna do that?" In other words, the edge cases are not compelling enough.
Chris
These kinds of properties can be implemented using traits: http://scg.unibe.ch/Research/Rotor/index.html, unfortunately for .Net they never made it out of research ...
Pop Catalin
Thanks Jon. I'm enjoying your book very much by the way. I was just reading about generics last night and had this idea.
Jonathan Parker
@Jonathan: Glad your having fun with it - please mail me if you have any feedback, good or bad :)
Jon Skeet
@Jon: Will do. P.S. I would love to hear your thoughts on http://stackoverflow.com/questions/656564/
Jonathan Parker
+1  A: 

No.

Generic methods make sense, because they embody some (generic) operation that can sensibly be applied to different types.

But properties only make sense as uniquely named values with definite content. 'Generic properties', like you suggest, really only amounts to like-named properties with different signature and different content.

Tor Haugen
+1  A: 

Here's one example where it would have been handy for me, if it would have been possible.

var settings = new Settings();  
int timeout = settings<int>["CacheInMinutes"];

Where Settings loads an XML file of configuration variables.

That, compared to:

var settings = new Settings();  
int timeout = int.Parse(settings["CacheInMinutes"]);

Really not much of a difference, but hey, I still would have preferred the generic indexer.

Chris
Yeah but "int timeout = settings.Get<int>("CacheInMinutes");" is just as terse, and doesn't require language change/addition to implement.
Chris
Good one. Indexers look like a good use case:Session<User>["CurrentUser"] = new User();...var user = Session<User>["CurrentUser"];
Jonathan Parker