2013-11-22 45 views
1

我有一个字节数据数组,但是这个数组可以包含任何无符号数字(byte/ushort/uint/ulong)作为字节。一般从字节数组中检索不同的数字数据类型

这样做的问题是将数据再次检索到所需的类型:我希望将数据转换回处理程序类中所需的数据类型,而不是再次请求数据的数据类型(可以将返回的数据代表该值的字节数组)。

此外,ref或out变量,虽然是一种解决方案,是一个麻烦作为成员我指定不一定我返回类型(读显式枚举):

public enum SomeEnum : ulong 
{ 
// ... 
} 

的功能我现在有:

/// <summary> 
/// Get data (byte) 
/// </summary> 
public byte GetDataByte(byte dataIndex) 
{ 
    return this.Data[dataIndex]; 
} 

/// <summary> 
/// Get data (ushort) 
/// </summary> 
public ushort GetDataUshort(byte startingDataIndex) 
{ 
    ushort output = 0; 
    for (byte i = startingDataIndex; i < this.Data.Length && i < sizeof(ushort); i++) 
    { 
    output |= (ushort)(this.Data[i] << (i * 8)); 
    } 
    return output; 
} 

/// <summary> 
/// Get data (uint) 
/// </summary> 
public uint GetDataUint(byte startingDataIndex) 
{ 
    uint output = 0; 
    for (byte i = startingDataIndex; i < this.Data.Length && i < sizeof(uint); i++) 
    { 
    output |= ((uint)this.Data[i] << (i * 8)); 
    } 
    return output; 
} 

/// <summary> 
/// Get data (ulong) 
/// </summary> 
public ulong GetDataUlong(byte startingDataIndex) 
{ 
    ulong output = 0; 
    for (byte i = startingDataIndex; i < this.Data.Length && i < sizeof(ulong); i++) 
    { 
    output |= ((ulong)this.Data[i] << (i * 8)); 
    } 
    return output; 
} 

这可以合并成一个函数,我会怎么做呢?像

SomeEnum member = (SomeEnum)GetData<ulong>(dataIndex); 

GetData<byte>(0); 

public T GetData<T>(byte startingDataIndex) // T would be byte during runtime 
{ 
    return this.Data[dataIndex]; // Compiler: Er, T? Byte? what? 
} 

/// <summary> 
/// Get data (T) 
/// </summary> 
public T GetData<T>(byte startingDataIndex) 
{ 
    T output = 0; // Compiler: derp, this isn't an integer. 
    for (byte i = startingDataIndex; i < this.Data.Length && i < System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)); i++) 
    { 
    output |= (T)(this.Data[i] << (i * 8)); // Compiler: nor is this! 
    } 
    return output; 
} 

还是我真是再好不过了,留下作为单独的功能和维护它们呢?

回答

1

不幸的是,你最终不得不为每个你想要反序列化的类型编写一个函数。这是因为你不能真正在T上使用逻辑运算符(&,|等)或数学运算符(=, - ,*等)。此外,T上的'numeric'类型没有约束所以你不会得到任何帮助。

如果你看看BinaryReader这个类,你会发现即使是微软写了一堆不同的函数来从字节流中读取不同的数据类型。另一方面,你可以编写某种通用函数,该函数实际上可以路由到正确的函数,并以这种方式返回结果。虽然它会更方便,但会有性能损失,但这可以接受,这取决于您的整体设计方法。例如:

public T ReadData<T>(int startIndex) 
{ 
    Type t = typeof(T); 

    if (t == typeof(int)) 
    { 
    return (T)(object)ReadInt(startIndex); 
    } 
    else if(t == typeof(byte)) 
    { 
    return (T)(object)ReadByte(startIndex); 
    } 
    else 
    { 
    string err = string.Format("Please support the type {0}", t); 
    throw new NotSupportedException(err); 
    } 
} 

同样,这不是100%理想的,但它会起作用。我使用了类似的方法,并且我发现在添加几个类型之后,在我知道它之前,我已经支持所有内部类型。

+0

我喜欢这种设计方法,但它不会编译为'ReadInt(startIndex);'会返回一个int(不是T)和'ReadByte(startIndex);'会返回一个字节(不是T)。因为编译器不知道如何将int或byte转换为T,所以不能将其转换为T. – kjhf

+0

等待,重复播放(T)(对象)有效。 :) – kjhf

+0

是的,对不起,我会更新代码。我刚刚从我头顶吹了一些东西。 –

0

您需要使用Marshall.Sizeof()而不是sizeof()才能计算泛型类型的大小。否则,它很简单。

public static T GetData<T>(byte startingDataIndex) 
    { 
     var length = Marshal.SizeOf(default(T)); 
     ulong buffer = 0; 
     for (var i = startingDataIndex; i < Data.Length && i < length; i++) 
     { 
      buffer |= (Data[i] << (i * 8)); 
     } 
     return (T)(object)buffer; 
    } 

公告称,| =操作不能被上通用的类型,因此它需要被存储在其中,我们必须假定能保持足够的字节的缓冲区ULONG使用。

+3

如果它如此微不足道,为什么不张贴您的答案。 –

+1

我没有看到“直线前进”的方面。 :\ 我已更新我的问题。 – kjhf

+0

点了。新的和改进的,现在也用简单直接的代码:)我第二次Nafals指出拳击/拆箱表现受到打击,并且可能更愿意去执行原始版本。至少在可能类型数量有限的情况下。 – Snorre

1

看看BitConverter课程。哪些应该能够处理转换为适当的类型或字节数组。如果您需要将它们转换为Enum,则需要使用Enum.ToObject。不幸的是,泛型不是模板,并不是真正为这种场景设计的。泛型适用于处理对象无关紧要或符合特定接口的场景。对于CLR没有一般描述符的情况,您需要专门研究并创建不同的方法。

相关问题