2009-09-06 93 views
1

這就是我到目前爲止所提出的,但它似乎並不是最優的,關於更好方法的任何想法?將不同值類型的數組轉換爲字節數組

public void ToBytes(object[] data, byte[] buffer) 
{ 
    byte[] obytes; 
    int offset = 0; 

    foreach (object obj in data) 
    { 
     if (obj is string) 
      obytes = System.Text.Encoding.UTF8.GetBytes(((string)obj)); 
     else if (obj is bool) 
      obytes = BitConverter.GetBytes((bool)obj); 
     else if (obj is char) 
      obytes = BitConverter.GetBytes((char)obj); 
     // And so on for each valuetype 

     Buffer.BlockCopy(obytes, 0, buffer, offset, obytes.Length); 
     offset += obytes.Length; 
    } 
} 

回答

4

好了,你可以有一個圖是這樣的:

private static readonlyDictionary<Type, Func<object, byte[]>> Converters = 
    new Dictionary<Type, Func<object, byte[]>>() 
{ 
    { typeof(string), o => Encoding.UTF8.GetBytes((string) o) }, 
    { typeof(bool), o => BitConverter.GetBytes((bool) o) }, 
    { typeof(char), o => BitConverter.GetBytes((char) o) }, 
    ... 
}; 

public static void ToBytes(object[] data, byte[] buffer) 
{ 
    int offset = 0; 

    foreach (object obj in data) 
    { 
     if (obj == null) 
     { 
      // Or do whatever you want 
      throw new ArgumentException("Unable to convert null values"); 
     } 
     Func<object, byte[]> converter; 
     if (!Converters.TryGetValue(obj.GetType(), out converter)) 
     { 
      throw new ArgumentException("No converter for " + obj.GetType()); 
     } 

     byte[] obytes = converter(obj); 
     Buffer.BlockCopy(obytes, 0, buffer, offset, obytes.Length); 
     offset += obytes.Length; 
    } 
} 

你還在指定轉換爲每個類型,但它的很多比它更緊湊的if/else形式。

有很多其他的方式來構建字典,順便說一句。你可以做這樣的:

private static readonly Dictionary<Type, Func<object, byte[]>> Converters = 
     new Dictionary<Type, Func<object, byte[]>>(); 

static WhateverYourTypeIsCalled() 
{ 
    AddConverter<string>(Encoding.UTF8.GetBytes); 
    AddConverter<bool>(BitConverter.GetBytes); 
    AddConverter<char>(BitConverter.GetBytes); 
} 

static void AddConverter<T>(Func<T, byte[]> converter) 
{ 
    Converters.Add(typeof(T), x => converter((T) x)); 
} 

我看到另一個答案已經建議二進制序列化。我個人不喜歡那種「不透明」的序列化方案。我喜歡以某種方式確切知道數據中會發生什麼,這意味着我可以將其移植到其他平臺。例如,我會指出,你目前的方案沒有給出任何分隔符 - 如果你有兩個字符串,你不知道哪個是停止的,另一個是否啓動。您也不會存儲類型信息 - 可能沒關係,但它可能不會。變長問題通常更重要。您可能會考慮使用長度前綴方案,如BinaryWriter中的方案。事實上,BinaryWriter可能是一個更簡單的解決方案。你可能想要仍然有一個代表地圖,但使他們的行動採取BinaryWriter和價值。然後,您可以通過反射來構建地圖,或者只是一個硬編碼的調用列表。

然後,您只需初始化一個包裝MemoryStreamBinaryWriter,將每個值適當寫入它,然後撥MemoryStream上的ToArray即可獲得結果。

+0

更重要的是,目前的方案不提供任何類型的信息。例如,您不知道您讀回的是「整數」還是「浮點數」。 – 2009-09-06 15:04:58

+0

@Mehrdad:這可能是一個問題,但它可能不是。類型信息*可以隱含 - 例如對象可以是類型中字段的值,其中整體類型是事先已知的。 – 2009-09-06 15:06:52

+0

謝謝你的答案。我知道變長問題,但試圖限制這個問題。我一直在使用的解決方案是將每個對象的長度存儲爲一個單獨的字節數組,並將其轉換後的數據複製到緩衝區。類型信息對於客戶端和服務器都是已知的,所以這不是問題。 您的解決方案看起來不錯,因爲服務器需要能夠與.NET客戶端和Java客戶端通信。 – remdao 2009-09-06 16:00:39

2

也許,你應該考慮使用BinaryFormatter代替:

var formatter = new BinaryFormatter(); 
var stream = new MemoryStream(); 
formatter.Serialize(stream, obj); 
byte[] result = stream.ToArray(); 

在那旁邊,有喜歡的Google Protocol Buffers一些不錯的序列化框架,如果你想避免重新發明輪子。

+0

感謝。如果有一種反序列化Java數據的方法,我會使用BinaryFormatter。我會研究谷歌協議緩衝區。你知道是否有Java版本? – remdao 2009-09-06 16:07:17

+1

remdao:是的,它有一個Java版本:http://code.google.com/p/protobuf/如果你想擁有一個跨平臺的序列化代碼,Jon還有另一個C#實現可以更好地適用於這種情況: http://code.google.com/p/protobuf-csharp-port – 2009-09-06 16:09:43

0

您可以使用一個StreamWriter寫入內存流和使用它的緩衝區:

{ 
       byte[] result; 
      using (MemoryStream stream = new MemoryStream()) 
      { 
       StreamWriter writer = new StreamWriter(stream); 
       writer.WriteLine("test"); 
       writer.WriteLine(12); 
       writer.WriteLine(true); 

       writer.Flush(); 

       result = stream.GetBuffer(); 
      } 

      using(MemoryStream stream=new MemoryStream(result)) 
      { 
       StreamReader reader = new StreamReader(stream); 
       while(! reader.EndOfStream) 
       Console.WriteLine(reader.ReadLine()); 
       } 
      } 
相關問題