Tyler Durden
Tyler Durden

Reputation: 1228

creating a byte array member for a structure in C#

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?

Upvotes: 3

Views: 4899

Answers (6)

Jevgenij Kononov
Jevgenij Kononov

Reputation: 1237

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]);
    }

Upvotes: 0

Nicholas Carey
Nicholas Carey

Reputation: 74307

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.

Upvotes: 2

jltrem
jltrem

Reputation: 12524

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

Upvotes: 1

Tyler Durden
Tyler Durden

Reputation: 1228

Use a class instead of a structure.

Upvotes: 1

John Alexiou
John Alexiou

Reputation: 29254

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)

Upvotes: 2

Habib
Habib

Reputation: 223282

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];
    }
}

Upvotes: 2

Related Questions