Создание аппаратно-зависимого делегата для метода расширения - PullRequest
3 голосов
/ 03 мая 2019

Я пишу библиотеку методов расширения для примитивных числовых массивов. Методы расширения имеют как обычную, так и аппаратную версию. Я пытаюсь использовать делегатов, чтобы у меня была одна точка входа для каждого метода. Например, рассмотрим простой метод расширения, который суммирует массив:

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

}

Это кажется невероятно уродливым, избыточным и нарушающим принципы СУХОГО. Это только один из десятков методов, которые я реализую, и продолжение этого текущего шаблона приведет к массивному классу ArrayExtensions.

Есть ли способ приблизиться к этому, который не потребует явных определений? Или, скорее, есть способ сделать это универсальным, но ограниченным только поддерживаемыми типами? Методы расширения будут доступны только для типов, представленных в приведенном выше коде.

1 Ответ

1 голос
/ 03 мая 2019

Вы можете немного упростить это, используя наследование.Это позволило бы избавиться от большей части этого.

Виртуальные вызовы немного быстрее, чем вызовы делегатов в качестве дополнительного бонуса.Используйте абстрактный базовый класс вместо интерфейса для повышения производительности.

Недостатком этого является то, что у вас меньше гибкости в выборе отдельных методов, которые вы хотите использовать.

КакВ качестве альтернативы вы можете подумать о создании этого кода на C # с использованием шаблонов T4.Они хорошо интегрированы в IDE.

Еще одна возможность - отражение.Это избавило бы не от всего этого, а от некоторых.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...