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?

Gary Barrett
  • 1,764
  • 5
  • 21
  • 33
Sunny Milenov
  • 21,990
  • 6
  • 80
  • 106
  • 9
    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. – Anthony Pegram Dec 23 '11 at 22:00
  • 7
    @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 property that is different from Weight". What does it even mean to parameterize a *property* with a *type*? – Eric Lippert Dec 24 '11 at 01:17
  • 2
    @EricLippert Generic properties do seem convenient, for example: `class Figure { public ColorT Color { 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. – BartoszKP Feb 18 '16 at 22:17
  • 3
    Also, `GetWeight();` also doesn't make sense, but I'm guessing you don't see generic methods as pointless. – BartoszKP Feb 22 '16 at 14:10
  • @BartoszKP 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 `` is certainly a parameter - specifically a generic type parameter. – Roman Starkov May 29 '17 at 19:32
  • @RomanStarkov It is about that, because Eric's main argument on *why* properties are not parametrized is that `Weight` 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. – BartoszKP Jun 07 '17 at 11:45

5 Answers5

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.

Timwi
  • 65,159
  • 33
  • 165
  • 230
  • 2
    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. – viggity Dec 23 '11 at 22:18
  • @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. – Timwi Dec 24 '11 at 16:54
  • 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. – supercat Sep 14 '12 at 18:32
  • 2
    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. – acarlon Aug 25 '13 at 03:58
  • 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. – acarlon Sep 07 '13 at 02:35
  • 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. – edthethird Aug 05 '14 at 18:31
  • @edthethird 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.AppData where the property for AppData is defined AppData AppData { get; } – SilverX Nov 12 '14 at 18:22
  • Ah but `Client` maintains a ton of state regarding configuration and user session... – edthethird Dec 04 '14 at 07:49
  • 1
    It does not follow, that generic properties don't make sense because `Weight` 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`, which does make sense (or see another example in my comment under the question). – BartoszKP Feb 22 '16 at 14:06
13

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

JamieSee
  • 12,696
  • 2
  • 31
  • 47
  • 5
    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. – Timwi Dec 24 '11 at 16:48
  • @Timwi 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. – JamieSee Dec 28 '11 at 16:08
  • @Timwi 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. – JamieSee Dec 28 '11 at 16:16
  • 4
    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. – Timwi Dec 28 '11 at 17:20
  • 1
    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. – Sunny Milenov Dec 28 '11 at 19:46
  • 4
    That post is pretty terrible. It's assuming that all properties have some backing storage which is not at all the case. – munificent Jan 06 '12 at 02:48
  • @munificent 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. – JamieSee Jan 28 '13 at 22:14
  • 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. – munificent Jan 30 '13 at 14:56
  • 3
    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`. Instead, it has to be the method `collection.OfType()` even though it takes no arguments. – munificent Jan 30 '13 at 14:57
  • 1
    The thing which doesn't make sense here: T Get and void Set(T t) are possible. Therefore, T Foo { 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. – Hatchling Apr 15 '16 at 20:28
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;
munificent
  • 11,946
  • 2
  • 38
  • 55
  • 9
    Actually, that problem already exists with generic methods (`M(a(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. – Timwi Sep 16 '12 at 19:51
  • @Timwi 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. – AnorZaken Jan 19 '15 at 13:45
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; }
}
Tom
  • 4,257
  • 6
  • 33
  • 49
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.

viggity
  • 15,039
  • 7
  • 88
  • 96
  • 3
    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. – Timwi Dec 24 '11 at 16:44
  • A better example would be IEnumerable _all, and IEnumerable All, which would iterate _all T, yielding any T's of type S. (Note that this can be achieved with the _all.OfType extension method.) – yoyo Sep 02 '13 at 03:19