Why does C# not allow generic properties?
Asked Answered
A

5

29

I was wondering why I can not have generic property in non-generic class the way I can have generic methods. I.e.:

public interface TestClass
{
   IEnumerable<T> GetAllBy<T>(); //this works

   IEnumerable<T> All<T> { get; } //this does not work
}

I read @Jon Skeet's answer, but it's just a statement, which most probably is somewhere in the specifications.

My question is why actually it is that way? Was kind of problems were avoided with this limitation?

Advice answered 23/12, 2011 at 21:43 Comment(6)
The answer might be "it doesn't make any sense." Properties to me are about state, whereas methods are about behaviors. It makes sense for a behavior to be generically applicable and the type to not matter, and indeed for the same method to be generically applicable for many different executions with many different types in the same instance, and it doesn't make sense for state to be generically applicable to the same degree. If you need generic state, you need a generic class. But I'm just musing.Andean
@AnthonyPegram is spot on here. How does it make any sense for a property of a thing to be parametrically polymorphic? A property of a thing is something like its colour, height, weight, and so on; the whole point of properties is that they are not parameterized. It doesn't make sense to have properties parameterized with formal parameters, and it certainly doesn't make any sense to say "I want my Car class to have a Weight<Fruit> property that is different from Weight<Giraffe>". What does it even mean to parameterize a property with a type?Cogent
@EricLippert Generic properties do seem convenient, for example: class Figure { public ColorT Color<ColorT> { get { ... } } ... } (possibly with some constraints on ColorT) to return color in a desired color space. Or quantities using different units, to refer to your example.Psychro
Also, GetWeight<Giraffe>(); also doesn't make sense, but I'm guessing you don't see generic methods as pointless.Psychro
@Psychro It's not about whether that call makes sense; the key in Eric's comment is that "the whole point of properties is that they are not parameterized", and <Giraffe> is certainly a parameter - specifically a generic type parameter.Flowers
@RomanStarkov It is about that, because Eric's main argument on why properties are not parametrized is that Weight<Giraffe> doesn't make sense. I pointed out, that this is pertains generic methods in the same way, so it cannot be a sensible reason for not having generic properties.Psychro
B
16

Technically, the CLR supports only generic types and methods, not properties, so the question is why it wasn’t added to the CLR. The answer to that is probably simply “it wasn’t deemed to bring enough benefit to be worth the costs”.

But more fundamentally, it was deemed to bring no benefit because it doesn’t make sense semantically to have a property parameterised by a type. A Car class might have a Weight property, but it makes no sense to have a Weight<Fruit> and a Weight<Giraffe> property.

Burnish answered 23/12, 2011 at 21:59 Comment(9)
I think if you look at some of the other answers, there is a reason why they don't allow it, it wasn't just a "too much time" concern.Germanous
@viggity: My answer isn’t just a “too much time” either. Also, I have left comments on the other answers. In short, they do not address the question.Burnish
Do you have any sense of why the CLR has three kinds of properties (read-only, write-only, and read-write), rather than simply specifying that a compiler which sees something that looks like an access to property foo should check whether a compatible method named get__foo or set__foo exists and has an isProperty attribute? The latter implementation would seem easier, would allow property getters or setters to be passed as delegates without wrapping, and would facilitate scenarios where a base class or interface has an abstract read-only property and a derived one has a read-write property.Cavanaugh
I don't understand the 'no sense semantically argument'. As is the case with Generic methods on a class, the purpose is often to make a subtype of the class generic rather than turn the whole class into something it is not (as in your example of turning a car into fruit). More likely it is to make some operation (get or set in the case of properties) on internal component of the class generic, such as internal vs external electronics or fuel, brake, rev gauges where an operation applies equally to each. Sounds more likely it was in the too hard basket.Caddie
Although, this is a boundary case and if generic properties were allowed, they would probably lead to semantic nonsense such as a gorilla class that has a generic hand property allowing the gorilla object to have chimpanzee hands. So, maybe not just the too hard basket as I originally thought.Caddie
well that's a terrible example! I have a Client class that provides instances of an AppData method, and that AppData is typed. Ideally I'd like to be able to cache a reference to AppData within the client.Lyda
@Lyda well I think the argument here is that you don't usually have 1 type of client that needs several types of AppData. It's different types clients accessing different types of AppData am I right? so it could be argued you are better with Client<T>.AppData where the property for AppData is defined AppData<T> AppData { get; }Tonie
Ah but Client maintains a ton of state regarding configuration and user session...Lyda
It does not follow, that generic properties don't make sense because Weight<Fruit> doesn't make sense. For every feature you can construct a stupid example, which doesn't ever imply that the feature doesn't make sense at all. In this context, consider Weight<Kilogram>, which does make sense (or see another example in my comment under the question).Psychro
K
13

This Generic Properties blog post from Julian Bucknall is a pretty good explanation. Essentially it's a heap allocation problem.

Kilter answered 23/12, 2011 at 22:10 Comment(10)
Like the other answer, this blog post does not at all address the question of generic properties, only generic fields. That does not explain why we couldn’t have generic properties.Burnish
@Burnish You seem a little confused, the blog post specifically addresses properties. The references to 'field' are explaining a method of solving one part of the generic property issue by adding a 'field' keyword to the language. That still ends up at a dead end due to the problem of the compiler having no way to reliably guess the correct allocation size for the object's backing store. This is the ultimate problem that is summed up in the last couple of paragraphs in the post.Kilter
@Burnish I'd also note that even the properties of the form get; set; are still backed by a field, it's just one automatically generated by the compiler. As such, it still has the same backing store problem.Kilter
That’s exactly what I’m saying. The problem is all with fields. Nothing in the blog entry says why we can’t have generic properties without a field. A property is just a get method (and optionally a set method), which could perfectly well be generic. It’s only fields that can’t be.Burnish
There are plenty of examples of get-only properties, which would not necessary be backed up by a field, and can do basic calculations. So, for these the "field" theory does not hold. Actually, I started wondering about this problem because of such a property.Advice
That post is pretty terrible. It's assuming that all properties have some backing storage which is not at all the case.Peptonize
@Peptonize It seems highly unlikely that a properly designed property would have no relation at all to a backing store -- unless, you're returning some constant value, in which case, why would you need a generic? If your property has a reference to ANY fields or other properties in the class, then it does in fact have a backing store behind it. I'd really like to see an example of what you're talking about.Kilter
A property will likely calculate a value that's related to the object's state, but that doesn't mean every property will have a 1-1 mapping to fields. Consider a Rect class that has fields for left, top, right, and bottom, but also has properties for width, height, x, y, area and perimeter. The last four don't have their own backing store because it's calculated from other state.Peptonize
Imagine a heterogeneous collection class. It might be nice to have an operation that gets all of the objects in the collection of a given type. If you had generic properties, that could be collection.OfType<Blah>. Instead, it has to be the method collection.OfType<Blah>() even though it takes no arguments.Peptonize
The thing which doesn't make sense here: T Get<T> and void Set<T>(T t) are possible. Therefore, T Foo<T> { get { ... } set { ...} } are possible. If there is some sort of silly internal reason for this not being the case, the compiler could just do a switcharoo beforehand, as aside from auto-properties and reflection (which could be specifically restricted) the two are functionally identical, just one has a nicer syntax in some cases.Condillac
P
3

My guess is that it has some nasty corner cases that make the grammar ambiguous. Off-hand, this seems like it might be tricky:

foo.Bar<Baz>=3;

Should that be parsed as:

foo.Bar<Baz> = 3;

Or:

foo.Bar < Baz >= 3;
Peptonize answered 6/1, 2012 at 2:52 Comment(2)
Actually, that problem already exists with generic methods (M(a<b,c>(d + 1)) vs. M(a < b, c > (d+1)), which is even much less contrived than your example) and it was specifically decided to take the breaking change anyway.Burnish
@Burnish That was unexpected. I would have assumed a,b,c,d are local variables and M is a method that takes 2 booleans. That would make most sense since if you define a local variable with the same name as a field, a property, a non-generic method, or even a type (both generic and non-generic) or a namespace, the local variable takes precedence due to shadowing. It's plain weird that shadowing works on pretty much anything except generic methods. I'm not really bothered by this limitation, but I do find it odd.Ence
G
0

I think not using an automatic getter/setter illustrates why this isn't possible without having "T" defined at the class level.

Try coding it, the natural thing to do would be this:

IEnumerable<T> _all;
IEnumerable<T> All
{
    get { return _all; }
}

Because your field uses "T", then "T" needs to be on the class the CLR knows what "T" is.

When you're using a method, you can delay definition of "T" until you actually call the method. But with the field/property, "T" needs to be declared in one place, at the class level.

Once you declare T on the class, creating a property becomes pretty easy.

public class TestClass<T>
{
    IEnumerable<T> All { get; }
}

usage:

var myTestClass = new TestClass<string>();
var stuff = myTestClass.All;

And just like the "T" type parameter on a method, you can wait until you actually instantiate your TestClass to define what "T" will be.

Germanous answered 23/12, 2011 at 22:13 Comment(2)
Your entire answer is all about fields, not properties; you are merely using the concept of automatically-implemented properties to stealthily refer to the implicit backing field. This answer does not address the question of generic properties, and the question wasn’t about auto-implemented generic properties.Burnish
A better example would be IEnumerable<T> _all, and IEnumerable<S> All<S>, which would iterate _all T, yielding any T's of type S. (Note that this can be achieved with the _all.OfType<S> extension method.)Ruzich
P
0

I made somthing like that. It type checks at run time.

public class DataPackage
{
    private dynamic _list;

    public List<T> GetList<T>()
    {
        return (List<T>)_list;
    }

    public void SetList<T>(List<T> list)
    {
        _list = list;
    }

    public string Name { get; set; }
}
Paradisiacal answered 29/3, 2017 at 7:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.