22

I need advice on structures.

I have 2 sections of code. The first section is as below:

namespace Project.GlobalVariables
{
    class IOCard
    {
        struct InputCard
        {
            public string CardNo;
            public int BaseAddress;
            public int LowerAddress;
            public int UpperAddress;
            public int[] WriteBitNo = new int[16];
            public int[] ReadBitNo = new int[16];
        }

        static InputCard[] InputCards = new InputCard[5];

        public static string ACardNo = InputCards[1].CardNo;
        public static string BCardNo = InputCards[2].CardNo;

    }
}

The second portion is as below:

private void Form1_Load(object sender, EventArgs e)
    {
        IOCard.ACardNo = "Card A";
        IOCard.BCardNo = "Card B";

        MessageBox.Show(IOCard.ACardNo);
        MessageBox.Show(IOCard.BCardNo);
    }

My plan is to be able to assign and retrieve InputCards component by using IOCard as shown in Form1_Load.

However, when I compile the code, I get the following error.

Error 1 'Project.GlobalVariables.IOCard.InputCard.WriteBitNo': cannot have instance field initializers in structs E:\Programming\New platform\StandardPlatform\StandardPlatform\Project\GlobalVariables.cs 16 26 StandardPlatform

Can someone tell me how to solve the error? Please advise. Thanks.

Here are the classes that I have attempted to create and use, but failed.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Project.GlobalVariables
{
    static class IOCard
    {
        public const int TotalInputCard = 10;
        public const int TotalOutputCard = 10;

        public  class InputCard
        {
            public string CardNo = "1";
            public int BaseAddress;
            public int LowerAddress;
            public int UpperAddress;
            public int[] WriteBitNo = new int[16];
            public int[] ReadBitNo = new int[16];
        }

        public class OutputCard
        {
            public string CardNo;
            public int BaseAddress;
            public int LowerAddress;
            public int UpperAddress;
            public int[] WriteBitNo = new int[16];
            public int[] ReadBitNo = new int[16];
        }

        public static InputCard[] InputCards = new InputCard[TotalInputCard];
        public static OutputCard[] OutputCards = new OutputCard[TotalOutputCard];

        public static int X100 = InputCards[0].WriteBitNo[0];
        public static int Y100 = OutputCards[0].WriteBitNo[0];
    }
}

I tried to use these in the Form_Load, like so:

private void Form1_Load(object sender, EventArgs e)
{
    IOCard.X100 = 1;
    IOCard.Y100 = 1;
} 

No matter how much I have tried to search on the net for answers, I have got nowhere.

Please advise. Thanks.

76484
  • 8,498
  • 3
  • 19
  • 30
JoJo
  • 221
  • 1
  • 2
  • 4

7 Answers7

13

In C#, a struct value is not a reference to an object in the way a value of a class type is. The value of a struct is the "union" of all the values of the instance fields of the struct.

Now, the default value of a struct type is the value where all those fields have their default values. Since the beginning of C#, the syntax:

new S()  // S is a value-type

where S is a struct type, has been equivalent to the default value of that struct. There is no constructor call! This is the exact same value which can (nowadays) also be written

default(S)  // S is a value-type

Now, things like

struct S
{
  int field = 42; // non-static field with initializer, disallowed!

  // ...
}

are illegal (cannot have instance field initializers in structs). They could give the impression that the field of a new S() would be 42, but in fact the field of new S() must be the default value of int (which is zero, distinct from 42).

With this explanation, you also see why it is not possible to create a non-static, zero-parameter constructor for a struct type, in C#.

Community
  • 1
  • 1
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
11

What's it's trying to say is that when you have InputCards = new InputCard[5]; it will allocate a block of memory 5 times the size of an InputCard structure and set all of its bytes to 0. There is no opportunity to execute the int[] WriteBitNo = new int[16]; and such assignments, so you cannot have them.

Your options are to either manually call an initializer for your structs or make it a class and manually initialize the InputCards array with 5 new instances of InputCard.

Gabe
  • 84,912
  • 12
  • 139
  • 238
6

You will neither be able to initialize a struct's fields nor define a default constructor to initialize it's fields. After looking at your struct, I recommend you use a class instead. It's not recommended to use a struct for a scenario where you have a bunch of fields.

decyclone
  • 30,394
  • 6
  • 63
  • 80
  • 1
    Guidelines on when to use `struct` : http://msdn.microsoft.com/en-us/library/y23b5415%28VS.71%29.aspx – decyclone Dec 10 '10 at 06:17
  • 1
    Incorrect. Microsoft has a C# programming guide article describing both how to _“initialize a struct's fields”_ and _“how to define a constructor to initialize its fields”_ right here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer What you're saying is impossible is actually both supported and easy. – Slipp D. Thompson Jan 14 '19 at 02:14
3

Try this. Initialize the InputCard with a factory function Create():

namespace Project.GlobalVariables 
{ 
    class IOCard 
    { 
        struct InputCard 
        { 
            public string CardNo; 
            public int BaseAddress; 
            public int LowerAddress; 
            public int UpperAddress; 
            public int[] WriteBitNo; 
            public int[] ReadBitNo; 

            static InputCard Create()
            {
                return new InputCard()
                {
                    CardNo = string.Empty,
                    WriteBitNo = new int[16],
                    ReadBitNo = new int[16]
                };
            }
        } 

        static InputCard[] InputCards = new InputCard[] 
        {
            InputCard.Create(),
            InputCard.Create(),
            InputCard.Create(),
            InputCard.Create(),
            InputCard.Create()
        };

        public static string ACardNo = InputCards[1].CardNo; 
        public static string BCardNo = InputCards[2].CardNo; 

    } 
}
John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • Thanks for the advice. How would I be able to do it in class? Any sample code? Thanks. – JoJo Dec 13 '10 at 00:38
0

Use class instead of structure. Structure is used for small types like Point, which are faster to create on the stack and copy, than to create dynamically and pass by reference.

Alex F
  • 42,307
  • 41
  • 144
  • 212
  • Sorry about that. Could not understand what you mean by "than to create dynamically "?? – Manish Basantani Dec 10 '10 at 06:15
  • 1
    When you pass a struct variable to or return it from a function, the entire variable is copied ("dynamically created"). When you pass a class variable, only a reference to that instance is sent. If the data is less than 16 bytes it's actually faster to copy the whole instance than to pass a reference to it. When a struct gets bigger, it gets slower because a lot more data must be copied whenever it is passed anywhere. – Excrubulent Nov 25 '13 at 19:43
0

Not sure about the exception, but i have a solution.

You should not use "struct" for this class, it is too much (and storing too much data). If you define it as "class", the same code would work fine.

Manish Basantani
  • 16,931
  • 22
  • 71
  • 103
0

Is there a particular reason why you want this to be a struct rather than a class?

If you make it a class, it works just fine.

Carson63000
  • 4,215
  • 2
  • 24
  • 38