Indexed Properties in C# 4.0
Executive summary:
- In C# 4.0 you can call parameterized properties declared in COM using the indexer syntax, for instance instead of excel.get_Range("a") you can now write excel.Range["a"].
- You can’t declare your own indexed properties from C#. We have no plans of adding the ability to declare your own properties with parameters. Instead, the recommended way is to use a type with an indexer.
- The feature is immediately available in Visual Studio 2010 Beta 2 for your indexing pleasure.
So I guess this hasn’t had a lot of press coverage so far (although Sam hinted about it). Even the published C# 4.0 language specification and the C# Future page still don’t mention it as of now. This is because we’ve implemented this feature very late in the cycle, as a DCR (Design Change Request). The language design team felt that we should complete the COM interop story in 4.0 and this one was the last missing piece of the puzzle. When Paul was in Redmond this summer, he was tasked with testing the IDE support for this feature, and I was helping out with the test infrastructure.
The new syntax
The pattern is very simple. Wherever you use COM interop and have to call get_X() and set_X(), now you can just call X[], which we feel is a more natural syntax:
// before
excel.get_Range("A1").set_Value(Type.Missing, "ID");
// after
excel.Range["A1"].Value = "ID";
Let’s also take Scott Hanselman’s example from Beta 1:
var excel = new Excel.Application();
excel.Visible = true;
excel.Workbooks.Add();
excel.get_ Range ( "A1" ) .Value2 = "Process Name";
excel.get_ Range ( "B1" ) .Value2 = "Memory Usage";
Now you can simplify this even further:
var excel = new Excel.Application();
excel.Visible = true;
excel.Workbooks.Add();
excel.Range["A1"].Value = "Process Name";
excel.Range["B1"].Value = "Memory Usage";
This is just syntactic sugar – the compiler emits calls to the get_ and set_ accessors behind the stage.
Omitting []
In case that all the parameters are optional and none of the arguments are specified, you should omit the empty []. Having Value[] is illegal.
This is the reason you can replace Value2 with Value in the example above: Value is an indexed property and you’re calling it without specifying any arguments – in this case we omit the brackets [] altogether. Earlier, without indexed properties support, we had to introduce the ugly Value2, because you otherwise had to call get_Value().
IDE support
My team, on the IDE side, provided IntelliSense support for this new language feature:
- completion list:
- parameter help:
- however Quick Info still shows you that in reality the call simply binds to the get_Range method:
As we were designing the feature, it turned out that adding compiler support for it is not the only tricky part. There were a couple of interesting problems in the IDE space as well. For example, what do you show in Quick Info for the following intexed property call?
A.B[C]++;
Do we now show get_B or set_B?
When the IDE can’t guess which accessor we’re talking about (for example, in incomplete code), we by default bind to the get_accessor.
Backwards compatibility
For backwards compatibility reasons, using the accessors get_ and set_ directly is still valid and available in IntelliSense, because we didn’t want to break all existing COM interop code out there.
Why not allow declaring indexed properties in C#?
A common question that we expect we’ll be getting is “why just consume? why not allow to declare such properties in C#?”. Well, the answer is not even that we first have to cost, design, spec, prototype, implement and test this feature, but rather that we think that declaring a type with an indexer is a preferred approach. It’s useful to separate the responsibilities:
- The property is there to get an object. The property belongs to the parent object.
- The indexer is there on the returned object to enumerate it. The indexer belongs to the returned object.
We shouldn’t be mixing these together.
Static or dynamic?
Accessing indexed properties is supported from both static and dynamic code.
Comments
Anonymous
October 20, 2009
If so, why not add full support, including definition?Anonymous
October 20, 2009
I wrote about this above :) Why not allow declaring indexed properties in C#?Anonymous
October 20, 2009
you have been able to declare indexed properties for a long time, so maybe the naming is getting confusing http://msdn.microsoft.com/en-us/library/aa288464(VS.71).aspx class Test { public string this[string key]... you're talking specifically about the .Value way of accessing the value through the propertyAnonymous
October 21, 2009
and you can even mimic these type of "indexed properties" http://codepaste.net/rzptfm am I missing something?Anonymous
October 21, 2009
Yes, it's all just about the syntax of accessing predefined COM or VB properties, it's the pure sugar of converting Value[] to get_Value().Anonymous
November 01, 2009
Full implementation of indexable properties would be an extremely desirable addition to the language. It should be left to the developers to decide to implement it as a separate type or as an indexable property. Please don't force such decisions upon us.Anonymous
November 01, 2009
Thanks Yurik. This feature is among others on a list for consideration for a hypothetical future release.Anonymous
November 13, 2009
Cool feature to simplify COM interop, but COM is NOT the future of .NET (I'm hopping you're thinking the same !). Please consider to implement nammed indexers (or indexed properties, whatever the name). I don't think it is so hard to do. C# is full of features inherited from Delphi Win32. In C# 4.0 you even added method optional parameters, another feature already in Delphi Win32 from years ! I can't believe we'll have to wait still 2 or 3 major C# releases to get indexed properties ! Indexed properties are a true need, stop working just for COM interop. Most of C# users do not care about COM, a very old Win32 technology ! We choose to use C# for WPF, Silverlight, Linq, ASP.NET, not for COM. Thanks in advance to think about this feature ! (and thanks of course for the good job, C# is cool, but it is still missing some very simple features).Anonymous
January 05, 2010
Hi, This artical is very useful for me. I am a .NET developer and always looking to learn something new. I would like to introduce another good C# blog, Have a look. http://CSharpTalk.com SonamAnonymous
February 18, 2010
Nice, I gues it also works for indexed properties defined in managed C++ ? To those who want indexed properties in C# : usually its better to have it a separate object because then you can implement IEnumerable<T> in addtion to the indexer, which allows LINQ and the System.Linq.Enumerable extension methods, something you don't get with indexed properties. Indexed properties force you to use a for-loop and you need a second property for 'Count', which is less convenient in the long run.Anonymous
April 23, 2010
Imagine a situation when you need to create a fascade for an ugly COM object or some other managed object. That COM object has indexed properties. And in order to aggregate it you need to create a new type what really doesn't look elegant in code. That's why, I agree with others - it should be up to developer to decide what to use. Indexed properties should be supported. Another thing - is extension properties - also seem to be useful in some cases.Anonymous
April 15, 2011
If you already have infrastructure for overloading, adding indexed properties to compiler is pretty easy. I was done it in my own compiler in 10 minutes (with reflection support) :D code.google.com/.../bamelg