2016-03-24 19 views
5

Bir arabelleğe bir akış okuyan ve verilen yapıya yükleyen bu iki işlevi kullanıyorum.Bu yapı işlevleri nasıl genel yapılır?

TestStruct1 ReadRecFromStream2(Stream stream) 
    { 
     byte[] buffer = new byte[Marshal.SizeOf(typeof(TestStruct1))]; 
     stream.Read(buffer, 0, 128); 
     GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); 
     try 
     { 
      return (TestStruct1)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(TestStruct1)); 
     } 
     finally 
     { 
      handle.Free(); 
     } 
    } 

    TestStruct2 ReadRecFromStream(Stream stream) 
    { 
     byte[] buffer = new byte[Marshal.SizeOf(typeof(TestStruct2))]; 
     stream.Read(buffer, 0, 128); 
     GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); 
     try 
     { 
      return (TestStruct2)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(TestStruct2)); 
     } 
     finally 
     { 
      handle.Free(); 
     } 
    } 
Ben yapılar birini almak için jenerik fonksiyonu içine bu birleştirmek istiyorum

, düzgün bir yol budur ne yapacağını sadece emin değilim.

Bu doğru yol mu?

private T ReadRecFromStream<T>(Stream stream) 
    { 
     byte[] buffer = new byte[Marshal.SizeOf(typeof(T))]; 
     stream.Read(buffer, 0, HeaderSize); 
     GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); 
     try 
     { 
      return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 
     } 
     finally 
     { 
      handle.Free(); 
     } 
    } 
+3

Bu oldukça iyi bir kod gibi görünüyor, – Gelootn

+0

Tamam, teşekkürler. Birisi bana yaptığım jenerik versiyonun yanlış olduğunu, ancak neden/nasıl yanlış olduğuna dair herhangi bir fikir vermediğini söyledi. Figürlü ben burada rica ediyorum. Teşekkürler! – pfinferno

+2

Muhtemelen 'HeaderSize' parametresini bir parametre olarak geçirmelisiniz ... Tüm T. – xanatos

cevap

2

Belki dan dönüştürmek için bu yöntemleri kullanabilir ve [] byte: Benzer çalışacak

T ReadRecFromStream<T>(Stream stream) 
    where T : struct 
{ 
    byte[] buffer = new byte[Marshal.SizeOf(typeof(T))]; 
    stream.Read(buffer, 0, buffer.Length); 
    return buffer.FromBytes<T>() 
} 

okuyun:

public static unsafe byte[] ToBytes<T>(this T value) 
    where T : struct 
{ 
    var result = new byte[Marshal.SizeOf(typeof(T))]; 
    fixed (byte* b = &result[0]) 
    { 
     var p = new IntPtr(b); 
     Marshal.StructureToPtr(value, p, false); 
    } 

    return result; 
} 

public static unsafe T FromBytes<T>(this byte[] bytes, int startIndex = 0) 
    where T : struct 
{ 
    fixed (byte* b = &bytes[startIndex]) 
    { 
     var p = new IntPtr(b); 
     return (T)Marshal.PtrToStructure(p, typeof(T)); 
    } 
} 

bu yöntemleri kullanarak şeklinde değiştirilebilir.

+0

Bunu beğendim, teşekkürler. Ancak fark ettim ki, yapılarımda farklı sayıda alan var, bu yüzden de yapının türünde bir yere geçmek zorunda mıyım? Orijinal iki işlevimden bu tür yapıya sahip olduğu için. – pfinferno

+0

@pfinferno Problemi anlamadım. İstediğiniz yapıları bu yöntemlere iletebilirsiniz. Yapının nasıl tanımlandığına dair meta bilgileri kaydetmeniz gerekmez. Genel, doğru arabellek oluşturmak için gereken tüm verileri içerir. Belki seni anlıyorum. Afedersiniz. –

+0

Maalesef, yapıyı yönteme nasıl aktaracağım konusunda kafam karıştı mı? Örneğin, 'test' denilen bir' TestStruct2 'yaptığımı varsayalım. Şu anda 'ReadRecFromStream' türünde 'TestStruct2' olduğu için test = ReadRecFromStream (stream) 'yapmaktayım. Ama gerçekleşmeyen genel işlevle mi? Kendimi aptalca karıştırıyor olabilirim. – pfinferno

İlgili konular