2011-10-07 80 views
6

使用.NET 4.0我可以通過使用Marshal類快速地將結構轉換爲字節數組和從字節數組轉換。例如,下面的簡單示例將大約每秒100萬次我的機器上這是對我來說已經足夠跑得快......WinRT和持久化結構的字節數組?

[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的,這就足夠了合理的下不可用出於安全原因,但這意味着我需要另一種方法來實現我的結構到/從字節數組。

我正在尋找一種適用於任何固定大小結構的方法。我可以通過爲每個知道如何將特定結構轉換成字節數組的結構編寫自定義代碼來解決這個問題,但這很乏味,我不禁感到有一些通用的解決方案。

+0

是二進制序列化的圖片嗎?另一個問題是,如果表現很重要,那麼涉及'AllocHGlobal'似乎很奇怪。 – user7116

+0

關於每次調用使用AllocHGlobal的好處。爲了提高效率,我的實際執行情況稍微複雜一點。它緩存len,arr和ptr,以便每次轉換爲字節的實際調用只涉及Marshal.StructureToPtr和Marshal.Copy。發佈的代碼只是一個簡單的例子。 –

+0

我用二進制序列化的問題是開銷。具有單個int32字段的結構將被序列化爲140字節。如果你的結構相當大,那麼這個開銷並不大,但在我的情況下,我有很多相對較小的對象。所以將結構轉換爲它包含的實際4字節對我來說是一個很大的節約。 –

回答

2

一種方法是表達與反思的組合(我會離開高速緩存作爲一個實現細節):

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

我喜歡構建表達式並編譯它以提供最佳性能的方法。 –

+0

我不認爲這將被允許在Windows應用商店的應用程序,因爲它是動態生成代碼來執行,是否正確? – Ani