-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C# should support indexed property #2144
Comments
nobody is interested in this? |
Well, I like the idea, but it's been out there for a while and rejected because of "ambiguous syntax" (not sure what is ambiguous about it myself). I like the idea, because semantically an indexed property is not an item in a collection. In fact I found this while checking to make sure that it hadn't been added since the last time I thought it would make things easier. In this case I was hoping to build a facade around Session, where most of the items are not just per Session but per window/tab. Index properties would make that trivial: Session.ExtensionMethodReturnsFacade().Property[page]. |
If the the type has an indexer you would get that syntax, class Foo { public int this[int index] { ... } }
class Bar { public Foo Foo { get; } }
var bar = new Bar();
int foo = bar.Foo[5]; And if you define |
@alrz and you see value in writing and instantiating a class in order to return an indexed value? The class Foo is never going to be used for anything other than the property Foo in Bar. As for the ambiguity -- I still don't see it, at least as far as the compiler is concerned. For people looking at the line in isolation, it wouldn't be clear whether it was an indexed property or a property for an indexer or Foo is just an array or dictionary, but I don't see how that matters. Any way you look at it, it is returning a value from something else. Looking at the definition will tell you what it is. |
From http://roslyn.codeplex.com/discussions/542484
And that nested type can be a struct, no allocations necessary. |
See, class Foo { public Bar this[int index] { ... } }
class Bar { public Foo Foo[int index] { ... } }
var bar = new Bar();
var foo = bar.Foo[5]; // which indexer I'm calling?
If it doesn't matter why don't you use a method instead? You are basically suggesting a method that has class Bar { public Foo Foo[int index] { ... } }
class Bar { public Foo Foo(int index) { ... } } Why is this important then? |
As for assignment, |
@HaloFour I gave an example of creating a facade around Sesssion where a page id is used to avoid collissions between tabs. Most of the properties should be indexed. C#, unlike VB, requires that an indexed property be the default property of a class. C# is conflating two entirely separate concepts, and in doing so being unclear. @alrz in VB, where that works, it calls the indexer in Bar (which returns a Foo), not the default property of a Foo (which returns a Bar). I don't see how it could be otherwise. As for why it matters, you hit upon it in your second message: assignment. A property handles both retrieving and setting a value. Also a method that returns a value is a calculation, while a property is state. As for ref return, I know the CLR supports it, but c# doesn't, and even if it did, that's not quite the same thing as a property. |
So your facade exposes a bunch of "named indexable" properties each taking the same index and each returning a different value? var x = obj.X[id];
var y = obj.Y[id]; Why would that be better than having one normal indexer which returns an object containing all of the properties for that page? var x = obj[id].X;
var y = obj[id].Y; Then you can pass all of the properties around without each consumer having to know/care about how they're indexed. Your use case sounds like the very design that the language should be discouraging. |
First let me say to that I understand that everything starts at -100, and this isn't a pony let alone a unicorn. I'm not trying to say "do it" but rather, "it shouldn't be rejected". Anyway... Sorta, not all of the properties will be indexed. Maybe half, pssoibly less. And doing it as you suggests works, but it creates an artificial distinction between properties on the wrapper and the indexed properties (class page with some properties). Session.w().D seems quite different from Session.w()[id].Y, as opposed to Session.w().D and Session.w().Y[id]. And I don't see why Session.w()[id].Y should be considered better than Session.w().Y[id](other than it works). The later seems more natural to me. The first seems to be saying "get the page of wrapper with the value id and then get the Y property" and the second "get the property Y of wrapper and then get the id value". But page doesn't really exist, it is an additional abstraction that is necessary only in order to make the access actually work. And since page doesn't model any real object and the properties aren't related in any way, the abstraction doesn't help you reason about the program. Again, I'm not saying this is a must-have or the best way (let alone the only) way to solve any particular problem. Just that it makes sense and would work, and that the "it's ambiguous" argument is, uhm, weak at best. It provides feature parity with VB. Don't reject the idea of someone doing it. |
Feature parity aside, I believe that this is still a valid extension to C#. The fact that it is possible in VB.NET shows that it is possible and CLR-supported, so that's not an impediment. The issues raised here seem to revolve around the way that it is used in a particular example... which seems to be a frivolous objection, since there are certainly other use cases which don't necessarily suffer from the same perceived problems. For instance, I have been working on an extendable wrapper for executing scripts and commands in an embedded PowerShell
This allows me to completely abstract the session state of the PowerShell I have other collections that I would also like to be able to access this way, and will end up coding as above, but would much prefer to do this:
Shorter code, much more self-explanatory, fewer issues with object initialization (no null assignment to the Another issue with the first code block above is that lambda expressions do funny things to garbage collection of the objects they capture. I've had to implement the And finally, there is not way to prevent or track external references to |
@alrz Nice thought, but in order to use an extension on an object I would need to expose that object, which I do not wish to do in this case. All interactions with the I suppoort #6136 in principle - I think it'd be a nice feature to have - but don't see a simple implementation path. Indexed properties (named indexers) already have been implemented in VB so there are no obvious impediments to C# implementation. This is a comparatively simple feature to add. |
To hide implementation you'd better use interfaces (#8127). |
@alrz I'm sorry but your extensions do not fit my needs, and interfaces do not prevent any of the issues I have raised. A reference to an interface can still be cached external to the class instance, the interface still needs to be assigned a concrete object whose lifecycle requires management, code is rendered less readable and so on. All of these points (and more) would be resolved by indexed properties. |
I could create a delegate to your indexed property and hold onto it forever, thereby holding a root reference to your Yes, it would be easy to add. It always has been. Yet the team intentionally didn't add it, and they continue to question their utility and discourage their pattern today. They never need a reason to not do something. |
@HaloFour In the current incarnation yes, you could hold all sorts of references, including a lot of unintentional ones. That's the problem. But how would that work for an indexed property? What would it look like to do so? Referencing the property itself without an index should fail at compile time and with an index it is not going to be returning a delegate (unless that's what is stored in the backing collection). How exactly would you get that delegate reference? How would you get a delegate to a standard property get/set method for that matter? Reflection? If bypassing via Reflection is reason not to have a feature then you might as well rip out
So what you're saying is I should never bother asking or showing support for features that might have come up before because The Team is all-wise, their decisions should never be questioned and no reasons need be given? Wow. Just wow. I thought that maybe if we could explain the utility of the feature, explain how we intend to use it and what benefits we would get from doing so, showed support for the feature and so on that maybe - just maybe - they might decide that the feature was actually worth taking another look at, and maybe one day I might get an improvement that will help me with this mess. Is that not the point of forums like this? |
You can create a delegate to any method, including property accessors. Simplest C# syntax would be through a closure: Func<string, object> d = index => runner.Variables[index];
Repeating the same questions will generally just result in the same answers. I think it's fine to question those answers, just as I think it's fine to question the questioning of those answers. The Team ultimately owns their language, though. |
@HaloFour Your lambda doesn't extract a delegate for the property get method, it closes around the parent object ( What I can do though is track those references down in the the code, or in the IL if necessary. Adding my
Have I implied otherwise? If so I apologize. But should I consider their dislike of the idea the final word and not try to show how it could be beneficial? |
This is already backlogged so considering all the things that can be done for C# it is probably up for C# 11. |
@Corey-M You're right, C# offers no direct syntax to obtain a delegate for a property. However, there are several proposals to add that syntax, not to say that any of them will be implemented. But property accessor methods are just normal methods so some languages could offer that syntax, or you could use reflection to obtain a delegate directly: PSRunner runner = new PSRunner();
PropertyInfo variablesProperty = typeof(PSRunner).getProperty("Variables");
MethodInfo getterMethod = variablesProperty.GetGetMethod();
Func<string, object> d = (Func<string, object>)Delegate.CreateDelegate(typeof(Func<string, object>), runner, getterMethod);
No, but you'd need a team member to champion the feature in order to get it implemented, even if you (or someone else) were to actually do the work. If they don't think that it's worth the cost in terms of effort and permanent support then it won't happen. In terms of showing how it could be beneficial, I'm not seeing anything new here. |
Issue moved to dotnet/csharplang #471 via ZenHub |
for example:
class A
{
int[] a, b;
public int pa[int index]
{
get { return a[index]; };
set { a[index]=value; };
};
public int pb[int index]
{
get { return b[index]; };
set { b[index]=value; };
};
};
The text was updated successfully, but these errors were encountered: