I'm defining structs to be received and sent over a communication channel between different devices and different programming languages.
For that I explicitly define their layout in memory using StructLayoutAttribute (sequential, pack=1 - in case it matters).
From the documentation, I know it works when the struct contains only fields. It seems to also work for 'simple' properties (with empty get; set;). However I don't know if it's always the case.
So my question regarding StructLayoutAttribute effect on properties is divided to two:
- Do simple properties (again, empty get; set;) behave the same as fields?
- How do other properties behave, for example properties that their get is a computation over other properties? Are they ignored (since I don't see an actual data item behind them)? Do they take memory?
Properties have no storage. StructLayoutAttribute
does not affect them at all.
Auto-properties access a generated backing field which is subject to StructLayoutAttribute
(since all fields are subject to this attribute). The order of those fields is not defined however.
Since get-properties that just compute a value have no storage they are not marshaled.
According to the documentation and my tests FieldOffsetAttribute can't be applied to properties. This leaves the question of LayoutKind.Sequential. According to this article the property fields appear in the end. Basically do not use auto properties if you care about the layout. Expand them and annotate the fields. Calculated properties do not appear in the memory layout of the struct.
Auto properties ({get; set;}
) have a publicly-inaccessible backing field that is created automatically. In fact, if you use reflection to look at the fields of a class that has an auto property, you can see that there is a private field for that property. The code below prints <Bar>k__BackingField
-- a weird field name, but a field name nonetheless!
I can't say I've tried StructLayoutAttribute
on a property. If it works, it surely just applies that same logic to the backing field.
using System;
using System.Reflection;
namespace ConsoleApplication10
{
class Program
{
static void Main(string[] args)
{
var fields = typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
Console.WriteLine(fields[0].Name);
}
}
class Foo
{
public int Bar { get; set; }
}
}