C#

2010-07-25 8 views
5

Bilinmeyen türünde bir ilkel türler dizisine bir bayt dizisi dönüştürme Aşağıdaki sorun var. Girişimi ilkel türler dizisine dönüştürmek istediğim bir dizi baytım var. Ama ben türünü bilmiyorum. (Bu bir dizi dizi olarak verilir). Sonuç olarak bir dizi nesneye ihtiyacım var.C#

Elbette, türler üzerinde bir anahtar kullanabilirim (yalnızca sınırlı sayıda), ancak bunun için daha iyi bir çözüm olup olmadığını merak ediyorum.

Örnek:

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 

bir algoritma bunun için var mı yoksa bir Düğmeyi

+0

Yazılı diziler mi arıyorsunuz yoksa sadece nesne []? –

+0

sadece nesne [] ConstructorInfo sınıfı ile bilinmeyen bir Oluşturucu çağırmak için nesne dizisini kullanmak istiyorum –

cevap

2

Bu kod bir olsun güvensiz kullanır bayt dizisi arabelleğine işaretçi, ancak bu bir sorun olmamalıdır.

[Düzenleme - yorum sonra kod değiştirildi]

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

Bir bypass dosyasının işaretçisine sahip olduğunuzda ve işaretçi aritmetiği yaptığınızda hem bir MemoryStream hem de bir işaretçiyi kullanmak için bir atık gibi görünüyor. –

+0

@Ben: Katılıyorum, tembel oldu ve şimdi değiştirdim. –

3

İşte Fikirlerimi kullanmalısınız:

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]); 
    } 
    .. 
} 

Tüm çözümler yukarıda byteData ve types arasında simetri varsayar
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(); 

Not. Onları dizileri oluşturmak ve doldurmak için yansıma kullanabilirsiniz

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

Veri Tamam görünüyor ama verilerin nasıl dönüştürüldüğünü bilmeniz gerekiyor _to_ byte []. Bayt sırası sorunları olabilir. –

+1

Bu çözüm (bence) bayt dizisinde 1'e 1 eşlemeyi yapar. Bu durumda, n baytların 1 ilkel türle eşleştirilmesini istiyorum (burada n, bayt cinsinden primitve türünün boyutudır (bir int için 4, bir kısa için 2, bir kayan için 8, ...)). Yoksa dönüştürme sınıfı diziyi işaretçi olarak kullanıyor mu? –

+0

@CommuSoft: Mesajımı güncelledim – abatishchev

0

:

Aksi takdirde asimetrik dizinin bir dizin içerecek simetrik dizi hazırlamak zorundayız. (Nedeniyle SByte için yanlış verilere hata işleyicisi edin):

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

Ve sonra:

[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

Bir BinaryReader kullanabilirsiniz

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

kirli küçük ama tiplerinin kontrol bazı yapılabilir ... sp, byteData sonraki okuma nereye işaret etmek için kullanılır işleri başka bir şekilde tahmin ediyorum ... ama bu sadece bir fikir. Eğer hoşuna gitmiyorsa, lütfen bana -1 yok. =)

 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; 

      } 
     }