为扩展方法创建特定于硬件的委托

时间:2019-05-02 23:29:51

标签: c# .net delegates

我正在为原始数字数组编写扩展方法库。扩展方法具有常规版本和硬件加速版本。我正在尝试使用委托,以便每个方法可以有一个入口点。例如,考虑对数组求和的简单扩展方法:

public static class ArrayExtensions
{

  #region Data Members

  private delegate TResult SumArrayDelegate<in TIn, out TResult>( TIn[] array );
  private static SumArrayDelegate<sbyte,int> SumArraySByte_;
  private static SumArrayDelegate<byte,int> SumArrayByte_;
  private static SumArrayDelegate<short,int> SumArrayShort_;
  private static SumArrayDelegate<ushort,int> SumArrayUShort_;
  private static SumArrayDelegate<int,int> SumArrayInt32_;
  private static SumArrayDelegate<uint,uint> SumArrayUInt32_;
  private static SumArrayDelegate<long,long> SumArrayInt64_;
  private static SumArrayDelegate<ulong,ulong> SumArrayUInt64_;
  private static SumArrayDelegate<float,float> SumArrayFloat_;
  private static SumArrayDelegate<double,double> SumArrayDouble_;


  #endregion

  #region Constructor

  static ArrayExtensions()
  {
    if( Avx2.IsSupported )
    {
      SumArraySByte_ = Avx2Utilities.Sum;
      SumArrayByte_ = Avx2Utilities.Sum;
      SumArrayShort_ = Avx2Utilities.Sum;
      SumArrayUShort_ = Avx2Utilities.Sum;
      SumArrayInt32_ = Avx2Utilities.Sum;
      SumArrayUInt32_ = Avx2Utilities.Sum;
      SumArrayInt64_ = Avx2Utilities.Sum;
      SumArrayUInt64_ = Avx2Utilities.Sum;
      SumArrayFloat_ = Avx2Utilities.Sum;
      SumArrayDouble_ = Avx2Utilities.Sum;
    }
    else if( Avx.IsSupported )
    {
      SumArraySByte_ = AvxUtilities.Sum;
      SumArrayByte_ = AvxUtilities.Sum;
      SumArrayShort_ = AvxUtilities.Sum;
      SumArrayUShort_ = AvxUtilities.Sum;
      SumArrayInt32_ = AvxUtilities.Sum;
      SumArrayUInt32_ = AvxUtilities.Sum;
      SumArrayInt64_ = AvxUtilities.Sum;
      SumArrayUInt64_ = AvxUtilities.Sum;
      SumArrayFloat_ = AvxUtilities.Sum;
      SumArrayDouble_ = AvxUtilities.Sum;
    }
    else
    {
      SumArraySByte_ = ArrayUtilities.Sum;
      SumArrayByte_ = ArrayUtilities.Sum;
      SumArrayShort_ = ArrayUtilities.Sum;
      SumArrayUShort_ = ArrayUtilities.Sum;
      SumArrayInt32_ = ArrayUtilities.Sum;
      SumArrayUInt32_ = ArrayUtilities.Sum;
      SumArrayInt64_ = ArrayUtilities.Sum;
      SumArrayUInt64_ = ArrayUtilities.Sum;
      SumArrayFloat_ = ArrayUtilities.Sum;
      SumArrayDouble_ = ArrayUtilities.Sum;
    }
  }

  #endregion

  public static int Sum( this sbyte[] array ) => SumArraySByte_( array );
  public static int Sum( this byte[] array ) => SumArrayByte_( array );
  public static int Sum( this short[] array ) => SumArrayShort_( array );
  public static int Sum( this ushort[] array ) => SumArrayUShort_( array );
  public static int Sum( this int[] array ) => SumArrayInt32_( array );
  public static uint Sum( this uint[] array ) => SumArrayUInt32_( array );
  public static long Sum( this long[] array ) => SumArrayInt64_( array );
  public static ulong Sum( this ulong[] array ) => SumArrayUInt64_( array );
  public static float Sum( this float[] array ) => SumArrayFloat_( array );
  public static double Sum( this double[] array ) => SumArrayDouble_( array );

}

这似乎非常丑陋,多余,并且违反了DRY原则。这只是我正在实现的数十种方法之一,继续这种当前模式将导致大型ArrayExtensions类。

有没有一种方法不需要显式定义?或者更确切地说,是否有一种方法可以使这种泛型,但仅限于受支持的类型?扩展方法仅适用于以上代码中提供的类型。

2 个答案:

答案 0 :(得分:1)

您可以通过使用继承来简化此操作。这将摆脱大部分。

虚拟通话比代理通话稍快一些,这是附加的奖励。使用抽象基类而不是接口来提高性能。

缺点是,在选择要使用的各个方法时灵活性较差。

作为替代方案,您可以考虑使用T4模板生成此死记号C#代码。它们很好地集成到了IDE中。

另一种可能是反思。这并不能消除所有这些,而是​​其中一些。

答案 1 :(得分:0)

您可以将方法声明为:

        public static T Sum<T>(this T[] arry)
        {
            double sum = 0d;
            double dval = 0d;
            foreach (T val in arry)
            {
                if (double.TryParse(val.ToString(), out dval))
                {
                    try { sum += dval; }
                    catch (OverflowException) { break; }
                }
            }
            return (T)Convert.ChangeType(sum, typeof(T));
        }

或手动处理方法中的类型。