2009-08-24 2 views
6

Я пытаюсь выполнить некоторые общие операции с номерами, не зависящими от типа числа. Однако я не знаю, как использовать дженерики для этого. Первая идея заключалась в фильтрации входящих типов с помощью оператора where, но все типы номеров закрыты и поэтому недействительны для общего фильтра. Кроме того, дженерики не допускают стандартных числовых операций (добавление, сдвиг и т. Д.), Поэтому единственным решением, которое я могу придумать, является переписывание каждого метода в общем случае. Любые другие идеи?C#: общий интерфейс для чисел

Для справки Ниже приведен код, который я сначала попробовал:

private const int BYTE_SIZE = 8; 

    private const int UINT16_SIZE = 16; 

    private const int UINT32_SIZE = 32; 

    private const int UINT64_SIZE = 64; 

    public static byte[] ToBytes(UInt16[] pnaValues) 
    { 
     return ToSmaller<byte, UInt16>(pnaValues, BYTE_SIZE, UINT16_SIZE); 
    } 

    public static byte[] ToBytes(UInt32[] pnaValues) 
    { 
     return ToSmaller<byte, UInt32>(pnaValues, BYTE_SIZE, UINT32_SIZE); 
    } 

    .... 

    public static UInt16[] ToUInt16s(byte[] pnaValues) 
    { 
     return ToLarger<UInt16, byte>(pnaValues, UINT16_SIZE, BYTE_SIZE); 
    } 

    public static UInt16[] ToUInt16s(UInt32[] pnaValues) 
    { 
     return ToSmaller<UInt16, UInt32>(pnaValues, UINT16_SIZE, UINT32_SIZE); 
    } 

    ... 

    public static UInt64[] ToUInt64s(UInt32[] pnaValues) 
    { 
     return ToLarger<UInt64, UInt32>(pnaValues, UINT64_SIZE, UINT32_SIZE); 
    } 

    private static TLarger[] ToLarger<TLarger, TSmaller>(TSmaller[] pnaSmaller, int pnLargerSize, int pnSmallerSize) 
     where TLarger : byte, UInt16, UInt32, UInt64 
     where TSmaller : byte, UInt16, UInt32, UInt64 
    { 
     TLarger[] lnaRetVal = null; 
     int lnSmallerPerLarger = pnLargerSize/pnSmallerSize; 

     System.Diagnostics.Debug.Assert((pnLargerSize % pnSmallerSize) == 0); 

     if (pnaSmaller != null) 
     { 
      System.Diagnostics.Debug.Assert((pnaSmaller % lnSmallerPerLarger) == 0); 

      lnaRetVal = new TLarger[pnaSmaller.Length/lnSmallerPerLarger]; 

      for (int i = 0; i < lnaRetVal.Length; i++) 
      { 
       lnaRetVal[i] = 0; 

       for (int j = 0; j < lnSmallerPerLarger; j++) 
       { 
        lnaRetVal[i] = (lnaRetVal[i] << pnLargerSize) + pnaSmaller[i * lnSmallerPerLarger + j]; 
       } 
      } 
     } 

     return lnaRetVal; 
    } 

    private static TSmaller[] ToSmaller<TSmaller, TLarger>(TLarger[] pnaLarger, int pnSmallerSize, int pnLargerSize) 
     where TSmaller : byte, UInt16, UInt32, UInt64 
     where TLarger : byte, UInt16, UInt32, UInt64 
    { 
     TSmaller[] lnaRetVal = null; 
     int lnSmallerPerLarger = pnLargerSize/pnSmallerSize; 

     System.Diagnostics.Debug.Assert((pnLargerSize % pnSmallerSize) == 0); 

     if (pnaSmaller != null) 
     { 
      lnaRetVal = new TSmaller[pnaLarger.Length * lnSmallerPerLarger]; 

      for (int i = 0; i < lnaRetVal.Length; i++) 
      { 
       for (int j = 0; j < lnSmallerPerLarger; j++) 
       { 
        lnaRetVal[i * lnSmallerPerLarger + (lnSmallerPerLarger - 1 - j)] 
         = pnaLarger[i] >> (j * pnLargerSize); 
       } 
      } 
     } 

     return lnaRetVal; 
    } 

ответ

11

Там нет общего интерфейса для арифметических операций, осуществляемых числовыми типами. Generic operators может помочь решить вашу проблему.

+4

В частности, для этого случая 'Operator.Convert (значение TFrom)' может быть полезно. –

+0

Обратите внимание, что я не реализовал 'LeftShift' и' RightShift', но их было бы тривиально добавлять. –

0

Перезапись, вероятно, самая простая. Единственное другое решение, которое я могу придумать, состоит в том, чтобы выйти за рамки шаблонов, написать String, который представляет вашу функцию, с символами-заполнителями для типа, а затем заменить его на имя каждого типа и скомпилировать его во время выполнения.

Помимо первоначального удара, вызванного компиляцией, также будет сложно назвать эти функции.

+0

Портирование 'eval()' на C#? Черт возьми нет! :) –

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