2013-11-22 11 views
1

У меня есть массив данных из байтов, однако этот массив может содержать любое беззнаковое число (byte/ushort/uint/ulong) в виде байтов.Как правило, получение разных числовых типов данных из массива байтов

Проблема заключается в том, что данные снова возвращаются в требуемый тип: я хочу, чтобы ответственность за преобразование данных обратно в требуемый тип данных из класса обработчика, а не за запрос, запрашивающий данные снова (который мог бы преобразовать возвращенный байтовый массив, представляющий значение).

Кроме того, реф или из переменных, хотя одно из решений, являются нервотрепки в качестве членов я присваивающих не обязательно типа я возвращающегося (читай явные перечислений):

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 поэтому вы не получите от этого никакой помощи.

Если вы заглянете в класс BinaryReader, вы увидите, что даже Microsoft закончила писать кучу различных функций для чтения различных типов данных из потока байтов.

С другой стороны, вы могли бы написать какую-то общую функцию, которая по существу направлялась бы к правильной функции и возвращала бы результаты таким образом. Хотя было бы более удобно, было бы наказание за производительность, но это может быть приемлемым в зависимости от вашего общего подхода к дизайну.Например:

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). Вы не можете наложить на T либо потому, что компилятор не знал, как преобразовать int или byte в 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

пункт снят. новый и улучшенный, теперь также с прямым кодом :) Я второй Нафалс говорит о поражении производительности бокса/распаковки, и, вероятно, предпочел бы перейти к первоначальной реализации. По крайней мере, количество возможных типов ограничено. – Snorre

1

Посмотрите на класс BitConverter. Который должен иметь возможность обрабатывать преобразование в соответствующий тип или массив байтов. Если вам нужно преобразовать их в Enum, вам нужно будет использовать Enum.ToObject. К сожалению, дженерики не являются шаблонами и на самом деле не предназначены для этого сценария. Дженерики предназначены для сценариев, в которых объект, обрабатываемый вами, не имеет значения или соответствует определенному интерфейсу. Для таких вещей, где CLR не имеет общего дескриптора, вам нужно специализироваться и создавать разные методы.

Смежные вопросы