2009-04-20 89 views
0

我有一個閱讀通用函數,它的工作非常好。它從字節緩衝區讀取並返回特定類型C#泛型

public static T Read<T>() 
{ 
    // An T[] would be a reference type, and a lot easier to work with. 
    T[] t = new T[1]; 

    // Marshal.SizeOf will fail with types of unknown size. Try and see... 
    int s = Marshal.SizeOf(typeof(T)); 
    if (index + s > size) 
     // Should throw something more specific. 
     throw new Exception("Error 101 Celebrity"); 

    // Grab a handle of the array we just created, pin it to avoid the gc 
    // from moving it, then copy bytes from our stream into the address 
    // of our array. 
    GCHandle handle = GCHandle.Alloc(t, GCHandleType.Pinned); 
    Marshal.Copy(dataRead, index, handle.AddrOfPinnedObject(), s); 

    index += s; 

    // Return the first (and only) element in the array. 
    return t[0]; 
} 

問題:如何執行寫入功能?

public static T Write<T>() 
{ 
    // An T[] would be a reference type, and a lot easier to work with. 
    T[] t = new T[1]; 

    // Marshal.SizeOf will fail with types of unknown size. Try and see... 
    int s = Marshal.SizeOf(typeof(T)); 
    if (index + s > size) 
     // Should throw something more specific. 
     throw new Exception("Error 101 Celebrity"); 

    // Grab a handle of the array we just created, pin it to avoid the gc 
    // from moving it, then copy bytes from our stream into the address 
    // of our array. 
    GCHandle handle = GCHandle.Alloc(dataWrite, GCHandleType.Pinned); 
    Marshal.Copy(t, index, handle.AddrOfPinnedObject(), s); // ?? Problem 

    index += s; 
} 

「t」應該是byte []數組。我如何實現這一目標?

+4

首先,這隻適用於結構,第二,爲什麼不使用BinarySerializer? – 2009-04-20 06:20:25

回答

1

這是很多代碼放在SO上,但在這裏。 Marshal.Copy有幾個重載符合您的需求。

class Program 
{ 
    static void Main(string[] args) 
    { 
     TestStruct test = new TestStruct(); 
     test.Bar = 100; 
     test.Foo = 200; 

     using (MemoryStream ms = new MemoryStream()) 
     { 
      using (ObjectStream os = new ObjectStream(ms, false)) 
      { 
       os.Write(test); 
      } 
      ms.Seek(0, SeekOrigin.Begin); 
      Console.WriteLine(BitConverter.ToString(ms.ToArray())); 
      using (ObjectStream os = new ObjectStream(ms, false)) 
      { 
       TestStruct result = os.Read<TestStruct>(); 
       Console.WriteLine(result.Bar); 
       Console.WriteLine(result.Foo); 
      } 
     } 

     Console.ReadLine(); 
    } 
} 

struct TestStruct 
{ 
    public int Foo; 
    public int Bar; 
} 

class ObjectStream : Stream 
{ 
    private Stream _backing; 
    private bool _ownsStream = true; 

    public ObjectStream(Stream source) 
     :this(source, true) 
    { 
    } 

    public ObjectStream(Stream source, bool ownsStream) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 

     _backing = source; 
     _ownsStream = ownsStream; 
    } 

    public override bool CanRead 
    { 
     get 
     { 
      return _backing.CanRead; 
     } 
    } 

    public override bool CanSeek 
    { 
     get 
     { 
      return _backing.CanSeek; 
     } 
    } 

    public override bool CanWrite 
    { 
     get 
     { 
      return _backing.CanWrite; 
     } 
    } 

    public override void Flush() 
    { 
     _backing.Flush(); 
    } 

    public override long Length 
    { 
     get 
     { 
      return _backing.Length; 
     } 
    } 

    public override long Position 
    { 
     get 
     { 
      return _backing.Position; 
     } 
     set 
     { 
      _backing.Position = value; 
     } 
    } 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
     return _backing.Read(buffer, offset, count); 
    } 

    public override long Seek(long offset, SeekOrigin origin) 
    { 
     return _backing.Seek(offset, origin); 
    } 

    public override void SetLength(long value) 
    { 
     _backing.SetLength(value); 
    } 

    public override void Write(byte[] buffer, int offset, int count) 
    { 
     _backing.Write(buffer, offset, count); 
    } 

    /// <summary> 
    /// Writes a value type to the stream. 
    /// </summary> 
    /// <typeparam name="T">The type of value.</typeparam> 
    /// <param name="value">The value.</param> 
    /// <returns>The number of bytes written to the stream.</returns> 
    public int Write<T>(T value) 
    { 
     // An T[] would be a reference type, and alot easier to work with. 
     T[] t = new T[1]; 
     t[0] = value; 

     // Marshal.SizeOf will fail with types of unknown size. Try and see... 
     int s = Marshal.SizeOf(typeof(T)); 
     // Create a temp array. 
     byte[] target = new byte[s]; 

     // Grab a handle of the array we just created, pin it to avoid the gc 
     // from moving it, then copy bytes from our stream into the address 
     // of our array. 
     GCHandle handle = GCHandle.Alloc(t, GCHandleType.Pinned); 
     Marshal.Copy(handle.AddrOfPinnedObject(), target, 0, s); // ?? Problem 

     // Write to the stream. 
     Write(target, 0, s); 

     return s; 
    } 

    /// <summary> 
    /// Reads a value type from the stream. 
    /// </summary> 
    /// <typeparam name="T">The type to read.</typeparam> 
    /// <returns>The data read from the stream.</returns> 
    public T Read<T>() 
    { 
     // An T[] would be a reference type, and alot easier to work with. 
     T[] t = new T[1]; 

     // Marshal.SizeOf will fail with types of unknown size. Try and see... 
     int s = Marshal.SizeOf(typeof(T)); 
     byte[] target = new byte[s]; 

     // Make sure there is enough data. 
     if (Read(target, 0, s) != s) 
      throw new InvalidDataException("Not enough data."); 

     // Grab a handle of the array we just created, pin it to avoid the gc 
     // from moving it, then copy bytes from our stream into the address 
     // of our array. 
     GCHandle handle = GCHandle.Alloc(t, GCHandleType.Pinned); 
     Marshal.Copy(target, 0, handle.AddrOfPinnedObject(), s); 

     // Return the first (and only) element in the array. 
     return t[0]; 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing && _ownsStream) 
      _backing.Dispose(); 
     base.Dispose(disposing); 
    } 
} 
0

和上次一樣,你可能想使用BinaryWriter類。

public void Write<T>(T item) { 
    // An T[] would be a reference type, and alot easier to work with. 
    T[] t = new T[] { item }; 

    // Marshal.SizeOf will fail with types of unknown size. Try and see... 
    int s = Marshal.SizeOf(typeof(T)); 
    if (_index + s > _size) 
     // Should throw something more specific. 
     throw new Exception("Error 101 Celebrity"); 

    // Grab a handle of the array we just created, pin it to avoid the gc 
    // from moving it, then copy bytes from our array into the stream. 
    GCHandle handle = GCHandle.Alloc(t, GCHandleType.Pinned); 
    Marshal.Copy(handle.AddrOfPinnedObject(), _stream, _index, s); 

    _index += s; 
}