2010-07-25 6 views
5

Ich habe das folgende Problem. Ich habe ein Array von Bytes, die ich in ein Array von primitiven Typen konvertieren möchte. Aber ich kenne den Typ nicht. (Dies wird als ein Array von Typen angegeben). Als Ergebnis brauche ich ein Array von Objekten.Konvertieren eines Byte-Arrays in ein Array von primitiven Typen mit unbekanntem Typ in C#

Natürlich könnte ich einen Schalter auf den Typen verwenden (es gibt nur eine begrenzte Anzahl von ihnen), aber ich frage mich, ob es eine bessere Lösung dafür gibt.

Beispiel:

byte[] byteData = new byte[] {0xa0,0x14,0x72,0xbf,0x72,0x3c,0x21} 
Type[] types = new Type[] {typeof(int),typeof(short),typeof(sbyte)}; 

//some algorithm 

object[] primitiveData = {...}; 
//this array contains an the following elements 
//an int converted from 0xa0,0x14,0x72,0xbf 
//a short converted from 0x72, 0x3c 
//a sbyte converted from 0x21 

Gibt es einen Algorithmus für dieses oder sollte ich einen Schalter

+0

Haben Sie nach typisierten Arrays oder nur Objekt [] gesucht? –

+0

Nur Objekt [] Ich möchte das Objekt-Array verwenden, um einen unbekannten Konstruktor mit der ConstructorInfo-Klasse –

Antwort

2

Dieser Code verwendet unsichere eine bekommen Zeiger auf den Byte-Array-Puffer, aber das sollte kein Problem sein.

[Bearbeiten - geändert Code nach comment]

byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 }; 
Type[] types = new Type[] { typeof(int), typeof(short), typeof(sbyte) }; 

object[] result = new object[types.Length]; 
unsafe 
{ 
    fixed (byte* p = byteData) 
    { 
     var localPtr = p; 
     for (int i = 0; i < types.Length; i++) 
     { 
      result[i] = Marshal.PtrToStructure((IntPtr)localPtr, types[i]); 
      localPtr += Marshal.SizeOf(types[i]); 
     } 
    } 
} 
+1

Scheint wie eine Verschwendung, einen MemoryStream und einen Zeiger zu verwenden, wenn Sie nur einen Zeiger auf ByteData haben und Zeigerarithmetik tun können. –

+0

@Ben: Ich stimme zu, es war faul von meiner Seite, und ich habe es jetzt geändert. –

3

Hier ist meine Ideen:

object[] primitiveData = new object[byteData.Lenght]; 
for (int i = 0; i < bytesData.Lenght; i++) 
{ 
    primitiveData[i] = Converter.ChangeType(bytesData[i], types[i]); 
} 

object[] primitiveData = new object[bytDate.Lenght]; 
for (int i = 0; i < bytesDate.Lenght; i++) 
{ 
    Type t = types[i]; 
    if (t == typeof(int)) 
    { 
      primitiveData[i] = Convert.ToInt32(bytesDate[i]); 
    } 
    else if (t == typeof(short)) 
    { 
      primitiveData[i] = Convert.ToInt16(bytesDate[i]); 
    } 
    .. 
} 

var dic = new Dictionary<Type, Func<byte, object>> 
{ 
    { typeof(int), b => Convert.ToInt32(b) }, 
    { typeof(short), b => Convert.ToInt16(b) }, 
    ... 
}; 

byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 }; 
Type[] types = new Type[] { typeof(int), typeof(short), typeof(sbyte) }; 

List<object> list = new List<object>(primitiveData.Length); 
for (int i = 0; i < primitiveData.Length; i++) 
{ 
    Byte b = byteData[i]; 
    Type t = types[i]; 
    Func<byte, object> func = dic[t]; 
    list.Add(func(b)); 
} 
object[] primitiveData = list.ToArray(); 

byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 }; 
// delegates to converters instead of just appropriate types 
Func<byte, object>[] funcs = new Func<byte, object>[] 
{ 
    b => Convert.ToInt32(b), 
    b => Convert.ToInt16(b), 
    b => Convert.ToSByte(b) 
}; 

List<object> list = new List<object>(primitiveData.Length); 
for (int i = 0; i < primitiveData.Length; i++) 
{ 
    Byte b = byteData[i]; 
    Func<byte, object> func = funcs[i]; 
    list.Add(func(b)); 
} 
object[] primitiveData = list.ToArray(); 

Beachten Sie, dass alle meine Lösungen über die Symmetrie zwischen byteData und types annimmt.

Andernfalls müssen Sie eine symmetrische Anordnung herzustellen, die einen Index von asymmetrischen Anordnung enthält:

byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 }; 
Type[] types = new Type[] { typeof(int), typeof(short), typeof(sbyte) }; // asymmetric 
int[] indexes = new int[] { 0, 0, 0, 0, 1, 2 }; // symmetric 
+0

Looks OK, aber Sie müssen wissen, wie die Daten _to_ byte [] konvertiert wurden. Es könnte Probleme mit der Byte-Reihenfolge geben. –

+1

Diese Lösung (ich denke) macht eine 1-zu-1-Zuordnung auf dem Byte-Array. In diesem Fall möchte ich eine Zuordnung von n Bytes zu 1 primitiven Typ (wobei n die Größe des Primitivtyps in Bytes ist (4 für einen Int, 2 für eine kurze, 8 für einen Float, ...)). Oder verwendet die Convert-Klasse das Array als Zeiger? –

+0

@CommuSoft: Ich habe meinen Beitrag aktualisiert – abatishchev

0

Sie Reflexion können die Arrays erstellen und sie zu füllen. (Beachten Sie die Fehlerbehandlung durch falsche Daten für SByte):

[TestMethod] 
    public void MyTestMethod() { 
    byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 }; 
    Type[] types = new Type[] { typeof(int), typeof(short), typeof(sbyte) }; 

    List<Array> result = new List<Array>(); 

    foreach (var type in types) { 
     Type arrayType = type.MakeArrayType(); 
     ConstructorInfo ctor = arrayType.GetConstructor(new Type[] { typeof(int) }); 
     Array array = (Array)ctor.Invoke(new object[] { byteData.Length }); 

     for (int i = 0; i < byteData.Length; i++) { 
      byte b = byteData[i]; 
      try { 
       array.SetValue(Convert.ChangeType(b, type), i); 
      } catch { 
       Console.WriteLine("Error with type {0} and value {1}", type, b); 
      } 
     } 

     result.Add(array); 
    } 

    // ------------------- 
    // show result 
    foreach (var array in result) { 
     Console.WriteLine(array.GetType()); 
     foreach (var item in array) { 
      Console.WriteLine(" {0}", item); 
     } 
    } 
    } 
0

Sie könnten verwenden, um eine BinaryReader:

public static IEnumerable<object> ConvertToObjects(byte[] byteData, Type[] types) 
{ 
    using (var stream = new MemoryStream(byteData)) 
    using (var reader = new BinaryReader(stream)) 
    { 
     foreach (var type in types) 
     { 
      if (type == typeof(short)) 
      { 
       yield return reader.ReadInt16(); 
      } 
      else if (type == typeof(int)) 
      { 
       yield return reader.ReadInt32(); 
      } 
      else if (type == typeof(sbyte)) 
      { 
       yield return reader.ReadSByte(); 
      } 
      // ... other types 
      else 
      { 
       throw new NotSupportedException(string.Format("{0} is not supported", type)); 
      } 
     } 
    } 
} 

Und dann:

byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 }; 
Type[] types = new Type[] { typeof(int), typeof(short), typeof(sbyte) }; 
object[] result = ConvertToObjects(byteData, types).ToArray(); 
0

wenig schmutzig, aber es funktioniert ... sp verwendet wird, um zu zeigen, wo ab dem nächsten in byteData zu lesen, kann die Überprüfung von Typen einige getan werden anders, denke ich ... aber das ist nur eine Idee. Also bitte nicht -1 mir wenn du es nicht magst. =)

 byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 }; 
     Type[] types = new Type[] {typeof(int),typeof(short),typeof(sbyte)}; 

     object[] primitiveData = new object[types.Length]; 
     int sp = 0; 

     for(int i=0; i<types.Length; i++) 
     { 

      string s = types[i].FullName; 
      switch(types[i].FullName) 
      { 
       case "System.Int32":{ 
        primitiveData[i] = BitConverter.ToInt32(byteData, sp); 
        sp += 4; 
       }break; 
       case "System.Int16": 
        { 
        primitiveData[i] = BitConverter.ToInt16(byteData, sp); 
        sp += 2; 
       }break; 
       case "System.SByte": 
        { 
        primitiveData[i] = (sbyte)byteData[sp]; 
        sp += 1; 
       }break; 

      } 
     } 
Verwandte Themen