2009-08-24 96 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 value)'可能很有用。 – 2009-08-24 22:43:51

+0

请注意,我没有实现'LeftShift'和'RightShift',但是它们会很容易添加。 – 2009-08-24 22:46:04

0

重写可能是最简单的。我能想出的唯一的其他解决方案是超越模板,编写一个代表您的函数的字符串,使用类型的占位符字符,然后用每个类型名称替换它并在运行时编译它。

除了由于编译造成的初始性能下降之外,它也很难调用这些函数。

+0

将'eval()'移植到C#中?没有! :) – 2013-02-15 19:27:39