2009-08-24 14 views
6

Próbuję wykonać pewne ogólne manipulowanie liczbą niezależną od typu numeru. Jednak nie wiem, w jaki sposób można użyć generycznych do tego. Pierwszym pomysłem było filtrowanie przychodzących typów za pomocą instrukcji where, ale wszystkie typy liczb są zamknięte i dlatego nie są ważne dla filtra generycznego. Ponadto generyczne nie pozwalają na standardowe operacje numeryczne (dodawanie, przesuwanie itp.), Więc jedynym rozwiązaniem, które mogę wymyślić, jest przepisanie każdej metody w sposób nietypowy. Jakieś inne pomysły?C#: Ogólny interfejs dla liczb

Dla odniesienia Oto kod, który początkowo próbował:

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

Odpowiedz

11

Nie ma wspólny interfejs dla operacji arytmetycznych realizowanych przez typów liczbowych. Generic operators może pomóc w rozwiązaniu problemu.

+4

W szczególności w tym przypadku użyteczne może być "Operator.Convert (wartość TFrom)". –

+0

Zauważ, że nie zaimplementowałem "LeftShift" i "RightShift", ale dodawanie ich byłoby banalnie proste. –

0

Przepisywanie jest prawdopodobnie najłatwiejsze. Jedyne inne rozwiązanie, jakie mogę wymyślić, to wyjście poza szablony, napisanie łańcucha znaków, który reprezentuje twoją funkcję, z znakami zastępczymi dla typu, a następnie zastąpienie go nazwą każdego typu i skompilowanie go w czasie wykonywania.

Poza początkowym działaniem wydajności związanym z kompilacją, trudno będzie wywołać te funkcje.

+0

Przenoszenie 'eval()' na C#? Na pewno nie! :) –

Powiązane problemy