c# - WinRT 和持久化结构与字节数组?

标签 c# .net windows-runtime microsoft-metro

使用 .NET 4.0,我可以通过使用 Marshal 类快速将结构与字节数组相互转换。例如,下面的简单示例将在我的机器上以每秒大约 100 万次的速度运行,这对于我的目的来说已经足够快了......

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

但 Marshal 类在 WinRT 下不可用,出于安全原因,这很合理,但这意味着我需要另一种方法来实现我的结构到/从字节数组。

我正在寻找一种适用于任何固定大小结构的方法。我可以通过为每个知道如何将该特定结构转换为字节数组并形成字节数组的结构编写自定义代码来解决这个问题,但这相当乏味,我忍不住觉得有一些通用的解决方案。

最佳答案

一种方法是结合使用表达式和反射(我将缓存作为实现细节):

// 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();
}

这样使用:

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

回读这段话,有点复杂:

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

关于c# - WinRT 和持久化结构与字节数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7682597/

相关文章:

c# - 将整数列表 (IEnumerable<int>) 转换为特定长度的元组列表 (IEnumerable<IEnumerable<int>>)

c# - 遍历 RichTextBox 使特定单词加粗

c# - 在 C# 中为 Win 8 Metro App 举办 Button 事件

c# - 使用 c# 和 xaml 在 Metro App 中显示 svg

c# - SetWinEventHook 窗口最大化事件

c# - 如何在 VS 2010 中为变量/字段/列表编写注释/文档?

.net - 如何正确记录扩展方法

javascript - 共享魅力在使用几次后开始出现错误

c# - 如何找到最接近任意(非成员)数字的数组元素?

c# - 从 C# .NET 控制台应用程序中显示图形?