-1

I am aware that in C# const can only be initialized at compile time. Which is related to what I am trying to do.

My objective is to write a constant array of constant objects in C#. How can I do that?

In order to explain my self, allow me to insert some code in C++ (I wrote some code some time ago) that explains what I am trying to do.

(In C++)

struct FD{
 string name; 
 double CE[2]; 
};

const FD models[2]={
     {"one",{2.0,1.0}},
     {"two",{3.0,4.0}}
};

Seems very simple, right? How can I do something like this in C#?


EDIT: (Attempted answer)

I found that you can do something like this in C#

 struct FD
    {
        public string name;
        public double[] CE;
    }
 static readonly FD[] models= new[]
   {
     new FD(){name="one" , CE= new double[]{1.0,2.0 } },
     new FD(){name="two", CE= new double[]{3.0,4.0}}         
   };

I wonder if this could be a good way to achieve my objective?

16
  • 4
    The closest would probably be a readonly ReadOnlyCollection of immutable structs/classes. But that's runtime and not compile time. Commented Jul 20, 2018 at 5:26
  • @Corak I found something like stackoverflow.com/a/309540/4451521 but it seems that is done on the heap not the stack and well it is not constant Commented Jul 20, 2018 at 5:30
  • 2
    In your code, the instances of FD are fully mutable (try models[0].name = "three";. and the contents of the array models can also be changed freely (try models[0] = new FD[...]). -- only re-assigning a completely different array to the variable models is prohibited. Commented Jul 20, 2018 at 5:41
  • 1
    @KansaiRobot - new FD("one", new[] { 1.0, 2.0 }) -- or the complete static readonly IReadOnlyList<FD> models = new ReadOnlyCollection<FD>(new List<FD> { new FD("one", new[] { 1.0, 2.0 }), new FD("two", new[] { 3.0, 4.0 }) }); Commented Jul 20, 2018 at 6:04
  • 1
    @KansaiRobot - Use readonly IReadOnlyList<FD> models = new ReadOnlyCollection<FD>([...]); as shown above. Then modifying models should not be allowed. Commented Jul 20, 2018 at 6:15

3 Answers 3

2

Sadly in C# you cannot define arrays or structures as const since the constructor can have runtime logic and therefore has to be executed at runtime. Your proposed solution is almost what you want, you just need a ReadonlyCollection<FD> to encapsulate your Array:

using System.Collections.ObjectModel;

static readonly ReadOnlyCollection<FD> models = new ReadOnlyCollection<FD>(new[]
{
    new FD(){name="one" , CE= new double[]{1.0,2.0 } },
    new FD(){name="two", CE= new double[]{3.0,4.0}}
});

Now you cannot change the reference of models (readonly) nor can you change the contents of it (ReadonlyCollection). You also cannot change any members of the FD instances since FD is a struct and the ReadonlyCollection creates another layer of indirection, basically copying your struct:

models = new ReadOnlyCollection<FD>(new FD[] { }); // Error CS0198  A static readonly field cannot be assigned to
models[0] = new FD(); // Error CS0200  indexer  is read only
models[0].name = "testname"; // Error CS1612  Cannot modify the return value

EDIT : I overlooked something, you can still change the array:

 models[0].CE[0] = 1; // compiles just fine

If possible you want to make CEreadonly too, but I'm not sure if your API allows that

Sign up to request clarification or add additional context in comments.

2 Comments

you forgot to make CE immutable.
@AlexeiLevenkov oh damn I overlooked that completely, hmm this makes it not that easy
1

Thinking outside the box :P

Others are providing you with great ideas but if you want to have truly const 4 values then you could just:

    const double FD_one_0 = 2.0;
    const double FD_one_1 = 1.0;
    const double FD_two_0 = 3.0;
    const double FD_two_1 = 4.0;

Comments

-1

In the end thanks to users Corak and Freggar I could come with something like this. (I suppose that model3 is the answer

Structs

 struct FD
    {
        public string name;
        public double[] CE;
    }

    struct FD2
    {
        public FD2(string name, IEnumerable<double>ce)
        {
            Name = name;
            CE = new ReadOnlyCollection<double>(new List<double>(ce));
        }
        public readonly string Name;   
        public readonly IReadOnlyList<double> CE;
    }

and the lists

 //This solution does not give the entire constant structure as name and FD[0] can be changed
        static readonly FD[] models= new[]
          {
              new FD(){name="one" , CE= new double[]{1.0,2.0 } },
              new FD(){name="two", CE= new double[]{3.0,4.0}}

          };

        //Here name can not be changed but models2[0] can be
        static readonly FD2[] models2 = new[]
        {
            new FD2("one",new double[]{1.0,2.0 }),
            new FD2("two", new double[]{3.0,4.0 })
        };

        //This is the best solution
        static readonly IReadOnlyList<FD2> models3 = new ReadOnlyCollection<FD2>(new[] {
            new FD2("one",new double[]{1.0,2.0 }),
            new FD2("two", new double[]{3.0,4.0 })
        }
        );

        //This is also a good solution but models4[0].CE[0] can be changed
        static readonly ReadOnlyCollection<FD> models4 = new ReadOnlyCollection<FD>(new[]
        {
             new FD(){name="one" , CE= new double[]{1.0,2.0 }},
             new FD(){name="two", CE= new double[]{3.0,4.0}}
        }); 

I guess models3 gives a good implementation to what I wanted to achieve.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.