WinRT and saving structure to and from byte array?

Using .NET 4.0 I can quickly convert a structure to and from an array of bytes using the Marshall class. For example, the following simple example will work about 1 million times per second on my machine, which is fast enough for my purposes ...

[StructLayout(LayoutKind.Sequential)] public struct ExampleStruct { int i1; int i2; } public byte[] StructToBytes() { ExampleStruct inst = new ExampleStruct(); int len = Marshal.SizeOf(inst); byte[] arr = new byte[len]; IntPtr ptr = Marshal.AllocHGlobal(len); Marshal.StructureToPtr(inst, ptr, true); Marshal.Copy(ptr, arr, 0, len); Marshal.FreeHGlobal(ptr); return arr; } 

But the marshal's class is not available under WinRT, which is reasonable enough for security reasons, but that means I need another way to reach my structure to / from the byte array.

I am looking for an approach that works for any fixed size structure. I could solve this problem by writing special code for each structure that knows how to convert this particular structure and form an array of bytes, but this is rather tedious, and I cannot help but feel that there is some general solution.

+6
source share
1 answer

One approach would be a combination of expressions and reflections (I will leave caching as an implementation detail):

 // Action for a given struct that writes each field to a BinaryWriter static Action<BinaryWriter, T> CreateWriter<T>() { // TODO: cache/validate T is a "simple" struct var bw = Expression.Parameter(typeof(BinaryWriter), "bw"); var obj = Expression.Parameter(typeof(T), "value"); // I could not determine if .Net for Metro had BlockExpression or not // and if it does not you'll need a shim that returns a dummy value // to compose with addition or boolean operations var body = Expression.Block( from f in typeof(T).GetTypeInfo().DeclaredFields select Expression.Call( bw, "Write", Type.EmptyTypes, // Not a generic method new[] { Expression.Field(obj, f.Name) })); var action = Expression.Lambda<Action<BinaryWriter, T>>( body, new[] { bw, obj }); return action.Compile(); } 

Used like this:

 public static byte[] GetBytes<T>(T value) { // TODO: validation and caching as necessary var writer = CreateWriter(value); var memory = new MemoryStream(); writer(new BinaryWriter(memory), value); return memory.ToArray(); } 

To read this, this is a little more important:

 static MethodInfo[] readers = typeof(BinaryReader).GetTypeInfo() .DeclaredMethods .Where(m => m.Name.StartsWith("Read") && !m.GetParameters().Any()) .ToArray(); // Action for a given struct that reads each field from a BinaryReader static Func<BinaryReader, T> CreateReader<T>() { // TODO: cache/validate T is a "simple" struct var br = Expression.Parameter(typeof(BinaryReader), "br"); var info = typeof(T).GetTypeInfo(); var body = Expression.MemberInit( Expression.New(typeof(T)), from f in info.DeclaredFields select Expression.Bind( f, Expression.Call( br, readers.Single(m => m.ReturnType == f.FieldType), Type.EmptyTypes, // Not a generic method new Expression[0])); var function = Expression.Lambda<Func<BinaryReader, T>>( body, new[] { br }); return function.Compile(); } 
+2
source

Source: https://habr.com/ru/post/898808/


All Articles