Open Youssef1313 opened 4 years ago
C# does currently support index initializers using System.Index
if the type has a settable indexer that accepts System.Index
. What C# doesn't currently do is to translate the System.Index
into an int
when the type doesn't have such an indexer. So what you're proposing would be that:
var items = new List<string>(source)
{
[^1] = "LastIsChanged"
};
be compiled into:
var $temp = new List<string>(source);
var index = $temp.Count - 1;
$temp[index] = "LastIsChanged";
var list = $temp;
So what you're proposing would be that:
var items = new List<string>(source) { [^1] = "LastIsChanged" };
be compiled into:
var $temp = new List<string>(source); var index = $temp.Count - 1; $temp[index] = "LastIsChanged"; var list = $temp;
This is exactly what I'm proposing. But I'm not getting the first part of your comment (probably due to lack of understanding of how things works together internally).
Here's an example, shows that an indexer initializer will work if there is a compatible this
property:
The problem is that List<T>
doesn't actually have an indexer method that accepts System.Index
as a parameter, so C# fakes it, but it doesn't do this with initializers today.
@HaloFour Got it!
But was there a reason that the runtime didn't define this indexer instead of the compiler being faking it?
The proposal only makes sense if there is a reason for the runtime not to define this indexer for certain types including List<T>
.
I believe it comes down to backward compatibility.
Modifying List<T>
to treat negative indexes as indexing from the end would have broken any code relying on an exception to terminate a loop.
So they introduced an index type.
But modifying List<T>
to add another indexer would also break back compatibility, both with overload choice and potentially reflection.
If you don't care about breaking existing code, many changes are possible - but you break trust with your developer community.
Then I think it just makes sense to "fake" things to work in initializers as well.
Currently, collection initializer works a bit different from dictionary and array ones. It doesn't calculate the desired length for the collection. It just calls Add
repeatly. Length related properties of the collection are essentially untouched. (For example, HashSet
doesn't guarantee to produce the same length of added items)
I'd love this feature, but it should be not easy to design for the corner cases. Bringing this syntax to array should be easier.
@huoyaoyuan HashSet doesn't in anyway allow indexing. So that case is unrelated.
for example, the following isn't allowed. So, this proposal doesn't apply for it.
using System.Collections.Generic;
var set = new HashSet<int>()
{
[0] = 5
};
But, the following is allowed, so this proposal applies to it:
using System.Collections.Generic;
var set = new List<int>()
{
[0] = 5 // Ignoring the fact that this will throw - i.e, assume some collection was passed to the ctor of List<T>.
};
I think we need to clarify whether this is just a hole in the "pattern index/range" implementation, or whether the current behavior is by-design.
Also, the title should probably be changed to mention "object initializers", not "collection initializers".
Indexers in collection initializers (Inspired from https://github.com/dotnet/roslyn/issues/47632)
Summary
An extension to the existing collection initializers syntax.
Motivation
Indexers provide a more readable syntax to access elements based on their position from the end (
[^1]
: last element,[^2]
: element before last, etc).However, indexers doesn't work with collection initializers currently. For example the following is allowed:
But the following is not:
Detailed design
The same way the current indexers are designed based on
System.Index
.Drawbacks
Currently, there is no way to set the last element in a collection initializer, even without using indexers.
The following code fails with
CS0165
:I don't know the reason for the current limitation (possibly false positive?). But I believe this should be worked on first.
Alternatives
Unresolved questions
Design meetings