3

I have a structure definition as follows:

public struct check
{
    public int[] x = new int[3]; //error
}

This is an error because you cant define an array size for a structure member in C#. I cant define the space for this array even in a default constructor in C# because parameterless constructors aren't allowed.

How do I do it? I know structures are immutable in C#.

I am using this structure not to create new objects but just to typecast objects of other class types.

check corp = (check )WmUtils.WM_GetObj(Attr);

Wm_getObj returns an object of check2 class type. Is readonly keyword helpful here?

Tyler Durden
  • 1,188
  • 2
  • 19
  • 35
  • Structures are *not* innately immutable in C#. It's just a really bad idea to have them be mutable, as it can lead to all sorts of problems. – David Yaw Oct 28 '13 at 17:36

6 Answers6

2

You can't have a parameter less constructor and you can't define an array with size in struct, this leaves you with a structure constructor taking a size as parameter like:

public struct check
{
    public int[] x;
    public check(int size)
    {
        x = new int[size];
    }
}
Habib
  • 219,104
  • 29
  • 407
  • 436
2

How about a fixed array buffer:

public unsafe struct Buffer
{
    const int Size=100;
    fixed byte data[Size];

    public void Clear()
    {
        fixed(byte* ptr=data)
        {
            // Fill values with 0
            for(int i=0; i<Size; i++)
            {
                ptr[i]=0;
            }
        }
    }

    public void Store(byte[] array, int index)
    {
        fixed(byte* ptr=data)
        {
            // find max elements remaining
            int N=Math.Min(index + array.Length, Size) - index;
            // Fill values from input bytes
            for(int i=0; i<N; i++)
            {
                ptr[index+i]=array[i];
            }
        }
    }

    public byte[] ToArray()
    {
        byte[] array=new byte[Size];
        fixed(byte* ptr=data)
        {
            // Extract all data
            for(int i=0; i<Size; i++)
            {
                array[i]=ptr[i];
            }
        }
        return array;
    }
}

unsafe class Program
{
    static void Main(string[] args)
    {
        Buffer buffer=new Buffer();
        // buffer contains 100 bytes
        int size=sizeof(Buffer);
        // size = 100
        buffer.Clear();
        // data = { 0, 0, 0, ... }
        buffer.Store(new byte[] { 128, 207, 16, 34 }, 0);

        byte[] data=buffer.ToArray();
        // { 128, 207, 16, 34, 0, 0, ... }
    }
}

(PS need to compile with allow unsafe code)

John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • 1
    It barks more than it bites. When done right it is perfectly safe. Just keep it simple. I **hate** they used a word like _unsafe_ for what is should be like _legacy_ or _allow pointers_. – John Alexiou Oct 25 '13 at 18:42
  • You are right! Its actually my mental block with it connotation – Tyler Durden Oct 25 '13 at 18:45
2

How about this:

struct Check
{
  private int[] _x ;
  public int[] X { get { return _x ?? new int[3]{0,0,0,} ; } }
}

This delays instantiation of the internal array until it is referenced. Presumably the array reference remains unchanged across the lifetime of the instance, so you don't really need a set accessor. The only real drawback here is that this is not thread-safe due to the implicit race condition on the first reference to the property X. However, since your struct putatively lives on the stack, it would seem that that is probably not a huge issue.

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
1

Given a check2 class:

  public class check2
  {
     public int x1 { get; set; }
     public int x2 { get; set; }
     public int x3 { get; set; }
  }

In your struct with a integer array, just add an operator to cast it from the class. The operator can initialize the array from the class instance:

  public struct check
  {
     public int[] x;

     public static explicit operator check(check2 c2)
     {
        return new check() { x = new int[3] { c2.x1, c2.x2, c2.x3 } };
     }
  }

Now you can create a check2 class and cast it to a check struct:

  check2 c2 = new check2() { x1 = 1, x2 = 2, x3 = 3 };
  check s = (check)c2;
  Console.WriteLine(string.Format("{0}, {1}, {2}", s.x[0], s.x[1], s.x[2]));

This outputs 1, 2, 3

jltrem
  • 12,124
  • 4
  • 40
  • 50
  • Actually its not always check2 typecasted, sometimes other structs too – Tyler Durden Oct 25 '13 at 18:33
  • You'll need to define an operator for each of them. There may be some shared code between them, but ultimately each conversion has to be defined. – jltrem Oct 25 '13 at 18:36
1

Use a class instead of a structure.

Arek Holko
  • 8,966
  • 4
  • 28
  • 46
Tyler Durden
  • 1,188
  • 2
  • 19
  • 35
0

This will probably help a lot. I have created structure MyX, Struct contains methods ToByte and to Struct So if you have byte array you can fill your struct array with bytes But be sure that your byte array alignment is correct. Hope this helps.

    public struct MyX
    {
        public int IntValue;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U1)]
        public byte[] Array;

        MyX(int i, int b)
        {
            IntValue = b;
            Array = new byte[3];
        }

        public MyX ToStruct(byte []ar)
        {

            byte[] data = ar;//= { 1, 0, 0, 0, 9, 8, 7 }; // IntValue = 1, Array = {9,8,7}
            IntPtr ptPoit = Marshal.AllocHGlobal(data.Length);
            Marshal.Copy(data, 0, ptPoit, data.Length);

            MyX x = (MyX)Marshal.PtrToStructure(ptPoit, typeof(MyX));
            Marshal.FreeHGlobal(ptPoit);

            return x;
        }
        public byte[] ToBytes()
        {
            Byte[] bytes = new Byte[Marshal.SizeOf(typeof(MyX))];
            GCHandle pinStructure = GCHandle.Alloc(this, GCHandleType.Pinned);
            try
            {
                Marshal.Copy(pinStructure.AddrOfPinnedObject(), bytes, 0, bytes.Length);
                return bytes;
            }
            finally
            {
                pinStructure.Free();
            }
        }
    }

    void function()
    {
        byte[] data = { 1, 0, 0, 0, 9, 8, 7 }; // IntValue = 1, Array = {9,8,7}
        IntPtr ptPoit = Marshal.AllocHGlobal(data.Length);
        Marshal.Copy(data, 0, ptPoit, data.Length);

        var x = (MyX)Marshal.PtrToStructure(ptPoit, typeof(MyX));
        Marshal.FreeHGlobal(ptPoit);

        var MYstruc = x.ToStruct(data);


        Console.WriteLine("x.IntValue = {0}", x.IntValue);
        Console.WriteLine("x.Array = ({0}, {1}, {2})", x.Array[0], x.Array[1], x.Array[2]);
    }
Jevgenij Kononov
  • 1,210
  • 16
  • 11