Click here to Skip to main content
15,439,117 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
In C#, I thought the rule was that any collection with an Add() function could participate in declarative initialisation? I have two such collections that are nested one inside the other. Is there a way to declaratively initialise it, rather than use procedural code in a constructor?

What I have tried:

I have got this code, complete with comment to show where I don't seem to be able to write anything the compiler understands:

C#
public class MyDataPoint
{
    public MyDataPoint( int x, int y ) { X = x; Y = y; }
    public int X { get; private set; } = 0;
    public int Y { get; private set; } = 0;
}

public class MyDataPlot : IReadOnlyCollection<MyDataPoint>
{
    public MyDataPoint this[ int index ] => _myDataPlot[ index ];
    public void Add( int x, int y ) => _myDataPlot.Add( new MyDataPoint( x, y ) );
    public int Count => _myDataPlot.Count;
    public IEnumerator<MyDataPoint> GetEnumerator() => _myDataPlot.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => _myDataPlot.GetEnumerator();
    private List<MyDataPoint> _myDataPlot = new List<MyDataPoint>();
}

public static class WorkWithData
{
    public static void DoSomethingWithDataStructure() { /* Code that works with the data structure */ }

    private static Dictionary<string,MyDataPlot> _dataStructure = new Dictionary<string,MyDataPlot>()
    {
        // Is there a way to initialise this without using code in a constructor?
    };
}
Posted
Updated 1-Feb-22 7:36am
v2

A collection initializer can work with multiple parameters - for example:
C#
private static Dictionary<string, MyDataPlot> _dataStructure = new()
{
    ["Foo"] = new MyDataPlot
    {
        { 0, 1 },
        { 2, 3 },
        { 4, 5 },
    },
};
You can't use the [0] = 1 syntax, since your class doesn't have an index setter.

Nifty trick: Combining constructor with collection initializer - The Old New Thing[^]
 
Share this answer
 
Because Add is a void method, you can't use it directly in an initializer.
Change it to return the MyDataPlot instance, and it works:
C#
public class MyDataPoint
    {
    public MyDataPoint(int x, int y) { X = x; Y = y; }
    public int X { get; private set; } = 0;
    public int Y { get; private set; } = 0;
    }

public class MyDataPlot : IReadOnlyCollection<MyDataPoint>
    {
    public MyDataPoint this[int index] => _myDataPlot[index];
    public MyDataPlot Add(int x, int y)
        {
        _myDataPlot.Add(new MyDataPoint(x, y));
        return this;
        }
    public int Count => _myDataPlot.Count;
    public IEnumerator<MyDataPoint> GetEnumerator() => _myDataPlot.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => _myDataPlot.GetEnumerator();
    private List<MyDataPoint> _myDataPlot = new List<MyDataPoint>();
    }

public static class WorkWithData
    {
    public static void DoSomethingWithDataStructure() { /* Code that works with the data structure */ }

    private static Dictionary<string, MyDataPlot> _dataStructure = new Dictionary<string, MyDataPlot>()
        {
            {"One", new MyDataPlot().Add(1, 1) }
        };
    }
 
Share this answer
 
Comments
Patrick Skelton 31-Jan-22 6:34am    
Thank you for that. Definitely a step in the right direction. Is it not possible to go one step further and just use nested curly braces that the compiler interprets as an implicit call to Add()? Is there any way to do that? (I'm just curious; your code is clear and concise and will do just fine.)
This is perhaps as close as I am going to get:

private static Dictionary<string,MyDataPlot> _dataStructure = new Dictionary<string,MyDataPlot>
{
    [ "One" ] = new MyDataPlot { { 2, 6 }, { 7, 4 } },
    [ "Two" ] = new MyDataPlot { { 5, 16 }, { 77, 34 } }
};

Taken from here: Dictionary Initialisation
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900