2011-10-07 18 views
6

.NET 4.0'ı kullanma Marşın sınıfını kullanarak bir yapıya bayt dizisine hızlı bir şekilde dönüştürebiliyorum. Örneğin, aşağıdaki basit örnek ... benim amaçlar için yeterince hızlıdır benim makinede saniyede 1 milyon civarında zamanlardaWinRT ve bir dizi bayttan gelen ve devam eden yapı?

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

çalışacaktır Ama Mareşal sınıfı yeterince makul WinRT altında kullanılamaz güvenlik nedenleriyle, ancak bu, bayt dizisine/yapısından yapılamamın başka bir yoluna ihtiyacım var demektir.

Herhangi bir sabit boyutlu yapı için çalışan bir yaklaşım arıyorum. Bu yapıyı bir bayt dizisine dönüştürmeyi ve bir bayt dizisi oluşturmayı bilen her bir yapı için özel kod yazarak çözebilirim ancak bu oldukça sıkıcıdır ve yardımcı olamıyorum, ancak bazı genel çözümlerin olduğunu hissediyorum.

+0

İkili serileştirme resim dışı mı? Başka bir soru, performansın önemli olup olmaması AllocHGlobal'ın dahil edilmesi tuhaf görünüyor. – user7116

+0

Her arama için AllocHGlobal kullanımı hakkında iyi bir nokta. Benim gerçek uygulamam daha verimli olmak için biraz daha karmaşıktır. Len, arr ve ptr'yi önbelleğe alır, böylece her gerçek çağrının bytes'e dönüştürülmesi yalnızca Marshal.StructureToPtr ve Marshal.Copy'yi içerir. Gönderilen kod sadece basitleştirilmiş bir örnektir. –

+0

İkili serileştirme ile yaşadığım sorun ek yük. Tek bir int32 alanına sahip bir yapı 140 baytlık bir şeye serileştirilir. Eğer yapılarınız oldukça büyükse, o zaman bu ek yük çok büyük değildir, fakat senaryonda göreceli olarak küçük nesnelerim var. Bu yüzden, yapıyı içerdiği gerçek 4 bayta dönüştürmek benim durumumda büyük bir tasarruf. –

cevap

2

Bir yaklaşım (ben bir uygulama ayrıntı olarak önbelleğe bırakacağım) İfadelerin ve Yansıma bir arada olacaktır:

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

şöyle Kullanılan:

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

bu geri okumak için ona biraz daha fazla:

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

En iyi performansı vermek için bir ifade oluşturma ve derleme yaklaşımını beğeniyorum. –

+0

Bunun için bir Windows Mağazası uygulamasında, yürütülecek kodu dinamik olarak oluşturduğundan, buna izin verileceğini düşünmüyorum, doğru mu? – Ani