I am trying to allocate an array of structures in C#. For example,
public struct Channel {
int ChannelId;
// other stuff goes here...
}
public struct FrameTraffic {
public int FrameId;
public int MaxChannels;
public Channel[] Channels;
public FrameTraffic(int dummyCS0568 = 0)
{
this.FrameId = 0;
MaxChannels = TableMgr.MaxChannels;
Channels = new Channel[TableMgr.MaxChannels];
}
}
But when I go to allocate an array of FrameTraffic structures, I see that Channels is null. This tells me that Channels is a reference rather than an array of structures. Am I correct? If so, then allocating the Channels array shouldn't embed the array into the structure, but simply satisfy the reference in the structure. I want the structures embedded. Is there a way to do this? Or am I incorrect in my assumptions?
Answering the later part of your question and disregarding any other problem. Yes you are correct, this will be a reference to an array. However, if you wanted to embed the array in the struct you can use a fixed sized buffer using the fixed and unsafe keywords. However that can only be known at design time, also it can only be of the following value types and not a user defined struct.
bool, byte, char, short, int, long, sbyte, ushort, uint, ulong, float, or double.
So in short, what you want to do is not possible, you may need to clarify why you need this or re-think your problem
You need to use the correct marshalling attribute, and it needs to have a fixed size, say 40
public struct FrameTraffic
{
public int FrameId;
public int MaxChannels;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public Channel[] Channels;
}
I was able to replicate the null issue not sure if its the same with yours :
There are two things that i think is possibly causing this :
You are just initializing the array with size but not assigning any values
You might be initializing FrameTraffic with default construct instead of what you have defined (this caused the actual NPE for me)
Below is how you can adjust your code: (I have hardcoded values which is brought by TableMgr.MaxChannels since i dont have that)
class Program
{
static void Main()
{
FrameTraffic fT = new FrameTraffic(0);
foreach (var item in fT.Channels)
{
Console.WriteLine(item.ChannelId);
}
Console.Read();
}
}
public struct Channel
{
public int ChannelId; //missing public exposer if you really want to reassign
// other stuff goes here...
}
public struct FrameTraffic
{
public int FrameId;
public Channel[] Channels;
public FrameTraffic(int dummyCS0568 = 0)
{
this.FrameId = 0;
const int MaxChannels = 1;
//array requires size and its values assigned here
Channels = new Channel[MaxChannels]{ new Channel { ChannelId = 1 } };
}
}
Related
Here is my code and it gives red squiggly line under the variable of the array declaration, stating,
Fixed size buffer fields may only be members of struct
float is a value type, so I don't quite understand this message.
What is the correct syntax to create public array of 13 elements (0 through 12; I ignore index 0)...
class clsUtility
{
public int UtilityId { get; set; }
public fixed float InterpolationFactorMonth[13]; // <-- HERE IS THE PROBLEM
}
If you want a fixed-sized array inline, that has to be declared within a struct, as per the compiler error. If you're actually happy with a reference to an array as normal, you need to differentiate between declaration and initialization. For example:
// Note: Utility isn't a great name either, but definitely lose the "cls" prefix.
class Utility
{
public int UtilityId { get; set; }
public float[] InterpolationFactorMonth { get; } = new float[13];
}
This declares a read-only property of type float[], and initializes it with a new array of 13 elements.
So first of all, it is not possible to use fixed in this case.
You could use public float[] InterpolationFactorMonth = new float[13];
To create an array of the size 13.
I have a program written in C which contains some nested structures of arrays like the following:
typedef struct
{
int s1var1[s1max1],
float s1var2[s1max2];
}struct1;
typedef struct
{
int s2var1[s2max1];
struct1 s2var2[s2max2];
*s2var2_ptr;
}struct2;
and I've written it in C# as following:
class Class1
{
public int[] s1var1 = new int[s1max1];
public float[] s1var2 = new float[s1max2];
}
class Class2
{
public int[] s2var1 = new int[s2max1];
public Class1[] s2var2 = new Class1[s2max2];
}
Is my translation true? What is wrong with this translation?
Thanks for your time.
public struct struct1
{
public int[] s1var1;
public float[] s1var2;
}
public struct struct2
{
public int[] s2var1;
public struct1[] s2var2;
}
public static void Main()
{
struct1 str;
str.s1var1 = new int[10];
str.s1var2= new float[10];
//or
struct1 str1 = new struct1();
str1.s1var1 = new int[10];
str1.s1var2= new float[10];
////
struct2 str2;
str2.s2var1 = new int[10];
str2.s2var2 = new struct1[10];
}
A struct type is a value type that is typically used to encapsulate
small groups of related variables, such as the coordinates of a
rectangle or the characteristics of an item in an inventory.
When a struct is created, the variable to
which the struct is assigned holds the struct's actual data. When the
struct is assigned to a new variable, it is copied. The new variable
and the original variable therefore contain two separate copies of the
same data. Changes made to one copy do not affect the other copy.
Microsoft source
Learn More About Structs
Classes and Structs
First, let's take a look at your code conceptually. In C you have some structures and in C# you have some classes. You will need to know that struct is different from class in many ways, not to mention that we have here some different languages as well, so writing a C# struct would be more suitable. However, if we look at your implementation, we see that on declaration level you try to assign some values to your arrays respectively. Are you sure the limits you use are defined and visible at the point you attempt to use them? Also, it would be much better if you would use a constructor and initialize your arrays there. And finally, I'm not sure at the point of Class2 you see Class1 which you attempt to use.
I started to learn about C# and I usually use C++.
There is a bunch of things that I'm trying to adapt, but std::array seem like impossible...
I just want to run this kind of code:
public struct Foo {};
public struct Test
{
public Foo value[20];
};
I don't want to allocate each time I use this struct and I don't want to use a class ever...
I saw fixed keyword but it works only for basic types...
There is not equivalent to something as simple as std::array?
I can even do that in C.
How would you sove this problem? (Even if it's still dynamically alocated..)
Using a fixed size buffer (fixed) is only possible for primitive types since its use is intended for interop. Array types are reference types, and so they can have dynamic size:
public struct Test
{
public Foo[] value;
}
Note however that copying the struct will only copy the reference, so the arrays will be identical. I suggest you either make the type immutable (by disabling writing to the array), or change struct to class and control cloning explicitly.
There is no such thing as a fixed size by-value array type in C# (although I have proposed it once). The closest thing you can get to it is a value tuple.
So it seems like there is no way to not do something as stupid as dynamically allocate something know at compile time. But that's C# so I just need to... try to close my eyes.
Anyway I did something to solve array alias and fixed array at the same time (I didn't ask about array alias on this question thought).
public abstract
class Array<T>
{
private T[] data;
protected Array(int size) { data = new T[size]; }
public T this[int i]
{
get { return data[i]; }
set { data[i] = value; }
}
};
public Alias : Array<int>
{
static public int Length = 10;
public Area() : base(Length) {}
};
And some people say it's quicker to write code with C#...
If someone have better I'll glady take it!
I'm looking for a data structure in .Net which keep heterogeneous structs contiguous in memory in order to be cpu-cache-friendly.
This type of data structure is explained in this blog : T-machine.org at the Iteration 4.
In .Net an array of value types (structs) keeps data contiguous in memory, but this is only working for a no-generic array.
I tried to create a ValueType[], but structs are boxed. So the references are contiguous in memory but not the real data.
After many tries I don't think this is possible natively in .Net. The only possible solution I see, it's to manually managed the seralization and deserialization of structs in a byte array, but I don't think it will be performant.
Did you find a native solution? or a better solution that mine?
Edit 1:
I'm trying to implement an entity-component-system as described in the T-Machine.org blog.
No. There is no way to do Iteration 4 in C#. You can't decide where in memory a .NET struct or class will be put. There is nothing similar to Placement New of C++.
But note that even Iteration 4 seems to have more problems than solutions:
At this point, our iterations are quite good, but we’re seeing some recurring problems:
Re-allocation of arrays when Components are added/removed (I’ve not covered this above – if you’re not familiar with the problem, google “C dynamic array”)
Fragmentation (affects every iteration after Iteration 1, which doesn’t get any worse simple because it’s already as bad as it could be)
Cross-referencing (which I skipped)
but
if you have struct of around the same size, the union trick could be enough...
public enum StructType
{
Velocity = 0,
Position = 1,
Foo = 2,
Bar = 3,
}
public struct Velocity
{
public int Vx;
public int Vy;
}
public struct Position
{
public int X;
public int Y;
public int Z;
}
public struct Foo
{
public double Weight;
public double Height;
public int Age;
}
public struct Bar
{
public int ColorR;
public int ColorG;
public int ColorB;
public int Transparency;
}
[StructLayout(LayoutKind.Explicit)]
public struct SuperStruct
{
[FieldOffset(0)]
public StructType StructType;
[FieldOffset(4)]
public Velocity Velocity;
[FieldOffset(4)]
public Position Position;
[FieldOffset(4)]
public Foo Foo;
[FieldOffset(4)]
public Bar Bar;
}
"officially" in C# there are no C unions. But thorugh the use of FixedLayout and FieldOffset you can create them. Note that they are totally incompatible with reference types, and clearly the size of the SuperStruct will be the size of the biggest possible element. In this case, 32 bytes, because Foo is 20 bytes, but there is some padding needed before and after it to align to the 8 bytes boundary.
Clearly your array would be of SuperStruct types. Note that by following the Iterion 4 example, the StructType isn't strictly necessary, because the types of the elements is written in other places.
Want to do this:
(EDIT: bad sample code, ignore and skip below)
struct RECORD {
char[] name = new char[16];
int dt1;
}
struct BLOCK {
char[] version = new char[4];
int field1;
int field2;
RECORD[] records = new RECORD[15];
char[] filler1 = new char[24];
}
But being unable to declare array sizes in struct, how do I reconfigure this?
EDIT: The reason for the layout is I'm using BinaryReader to read a file written with C structs. Using BinaryReader, and a C# struct union (FieldOffset(0)), I'm wanting to load the header as a byte array, then read it as it was intended originally.
[StructLayout(LayoutKind.Sequential)]
unsafe struct headerLayout
{
[FieldOffset(0)]
char[] version = new char[4];
int fileOsn;
int fileDsn;
// and other fields, some with arrays of simple types
}
[StructLayout(LayoutKind.Explicit)]
struct headerUnion // 2048 bytes in header
{
[FieldOffset(0)]
public byte[] headerBytes; // for BinaryReader
[FieldOffset(0)]
public headerLayout header; // for field recognition
}
Use fixed size buffers:
[StructLayout(LayoutKind.Explicit)]
unsafe struct headerUnion // 2048 bytes in header
{
[FieldOffset(0)]
public fixed byte headerBytes[2048];
[FieldOffset(0)]
public headerLayout header;
}
Alternativ you can just use the struct and read it with the following extension method:
private static T ReadStruct<T>(this BinaryReader reader)
where T : struct
{
Byte[] buffer = new Byte[Marshal.SizeOf(typeof(T))];
reader.Read(buffer, 0, buffer.Length);
GCHandle handle = default(GCHandle);
try
{
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
}
Unmanaged structures can contain embedded arrays. By default, these embedded array fields are marshaled as a SAFEARRAY. In the following example, s1 is an embedded array that is allocated directly within the structure itself.
Unmanaged representation
struct MyStruct {
short s1[128];
}
Arrays can be marshaled as UnmanagedType.ByValArray, which requires you to set the MarshalAsAttribute.SizeConst field. The size can be set only as a constant. The following code shows the corresponding managed definition of MyStruct.
C#VB
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
[MarshalAs(UnmanagedType.ByValArray, SizeConst=128)] public short[] s1;
}
I wouldn't use that pattern in the first place. This kind of memory mapping may be appropriate in c, but not in a high level language like C#.
I'd just write a call to the binary reader for each member I want to read. This means you can use classes and write them in a clean high level way.
It also takes care of endian issues. Whereas memory mapping will break when used on different endian systems.
Related question: Casting a byte array to a managed structure
So your code would look similar to the following (add access modifiers etc.):
class Record
{
char[] name;
int dt1;
}
class Block {
char[] version;
int field1;
int field2;
RECORD[] records;
char[] filler1;
}
class MyReader
{
BinaryReader Reader;
Block ReadBlock()
{
Block block=new Block();
block.version=Reader.ReadChars(4);
block.field1=Reader.ReadInt32();
block.field2=Reader.ReadInt32();
block.records=new Record[15];
for(int i=0;i<block.records.Length;i++)
block.records[i]=ReadRecord();
block.filler1=Reader.ReadChars(24);
return block;
}
Record ReadRecord()
{
...
}
public MyReader(BinaryReader reader)
{
Reader=reader;
}
}
Using unsafe code and fixed size buffer this can be done: http://msdn.microsoft.com/en-us/library/zycewsya.aspx
Fixed size buffers are inline-bytes of the struct. They don't live inside of a separate array like your char[] does.
Unless you really need a struct, you can do this with a class. A class is basically a struct, and will be used exactly the same way, but it can contain methods inside. One of these methods is the constructor, which will initialize default values inside it once you create a new instance with "new". To create a constructor, put a method with the same name of the class inside it. It may receive arguments if you wish.
class RECORD
{
public int dt1;
public char[] name;
public RECORD => name = new char[16] // if it is one-line the {} can be =>
}
class BLOCK
{
public char[] version;
public int field1;
public int field2;
public RECORD[] records;
public char[] filler1;
public BLOCK()
{
records = new RECORD[15];
filler1 = new char[24];
version = new char[4];
}
}
This way when you create a new item of type BLOCK, it will be pre-initialized:
var myblock = new BLOCK();
Console.WriteLine(myblock.records.Length); // returns 15
Console.WriteLine(myblock.records[0].Length); // returns 16
Console.WriteLine(myblock.filler1.Length); // returns 24