Перегрузка метода C # - PullRequest
       4

Перегрузка метода C #

0 голосов
/ 24 февраля 2012

У меня есть метод, который должен разрешить широкий спектр типов ввода. Существует две категории аргументов: аргументы типа границы и фактические аргументы ввода данных.

К граничным аргументам относятся, например, порядок, частота, количество точек и количество точек данных. Эти граничные аргументы имеют тип int и являются общими, независимо от фактического типа входного аргумента данных.

Фактические входные аргументы могут быть следующих типов: байты, int, короткие, uint, float, double, decimal, long и т. Д. Чтобы еще больше усложнить ситуацию, фактическими входными данными могут быть отдельные данные, или список или массив этот тип. Таким образом, фактический ввод может быть в виде List или uint [] и т. Д. Этот ввод в конечном итоге преобразуется в тип double - либо в виде отдельных данных, либо в double [].

Метод состоит из трех частей: первая часть проверяет достоверность граничных аргументов. Эта часть всегда применяет отношения фактического типа входных данных. Вторая часть проверяет и обрабатывает аргументы входных данных. Эта часть изменяется в зависимости от типа входных данных. Часть третья выполняет вычисления на основе данных и снова является общей.

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

Это то, что у меня сейчас есть:

// ... create lists to store data
static List<double> aList = new List<double>(8);
static List<double> fList = new List<double>(8);

public static double[] MyMethod(int numPts, int numData, object aValue, object fValue)
{
    // ... part 1
    if (numData < 2) throw new ArgumentOutOfRangeException("numberData must be >= 2.");
    if (numPts < 2) throw new ArgumentOutOfRangeException("numberPoints must be >= 2.");
    if (numData < numPts) throw new ArgumentOutOfRangeException("numberData must be
        >= numPts.");

    // ... part 2
    if (aValue is byte || aValue is short || aValue is int || aValue is long ||
        aValue is float || aValue is double || aValue is decimal ||
        aValue is List<byte> || aValue is byte[] || aValue is List<short> ||
        aValue is short[] || aValue is List<int> || aValue is int[] ||
        aValue is List<float> || aValue is float[] || aValue is List<double> ||
        aValue is double[])
    { }
    else throw new ArgumentException("a values must be of a numeric type.");

    double a = 0.0;
    if (aValue is byte || aValue is short || aValue is int || aValue is long ||
        aValue is float || aValue is double || aValue is decimal)
    {
        a = (double)aValue;
        // ... store individual values
        aList.Add(a);

        // ... create the x variable vector
        double[] x = aList.ToArray();     // a values
    }
    else if (aValue is List<byte> || aValue is List<short> || aValue is List<int> ||
             aValue is List<float> || aValue is List<double>)
    {
        // ... get the runtime type of the aValue object
        Type t = aValue.GetType();
        // ... convert the aValue object to a generic list
        IList tmp = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(t));
        // ... convert the generic list to a strongly typed list
        List<double> aValuesList = tmp.Cast<double>().ToList();

        // ... create the x variable vector
        double[] x = aValuesList.ToArray();     // a values
    }
    else
    {
        // ... process the vector input
        // ... get the runtime type of the aValue object
        Type t = aValue.GetType();
        // ... convert the aValue object to an array
        Array tmp = Array.CreateInstance(typeof([]).MakeGenericType(t), aValue.Length);
        // ... convert the generic array to a strongly typed array
        double[] x = tmp.Cast<double>().ToArray();
    }

    // ... part 3
    {
        // ... do calculations
    }
}

Ответы [ 5 ]

0 голосов
/ 24 февраля 2012

Если вы не хотите, чтобы вызывающая сторона преобразовывала свои данные в double[], то непременно сделайте это в вызываемой стороне. Но, пожалуйста, передайте это другой функции! Гораздо проще прочитать, что происходит:

public static double[] MyMethod(int numPts, int numData, object aValue, object fValue)
{
    //validation omitted for brevity
    // ... part 2
    double[] aValues = ToDoubleArray(aValue);
    // ... the rest
}

Готово! * * 1005

Вот реализация, хотя, несомненно, есть более надежная и / или эффективная:

private double[] ToDoubleArray(object aValue)
{
    if (aValue is byte || aValue is short || aValue is int || aValue is long
        || aValue is float || aValue is double || aValue is decimal)
        return new double[] { Convert.ToDouble(aValue) };

    if (aValue is IEnumerable)
        return ((IEnumerable)aValue).Select(Convert.ToDouble).ToArray();

    throw new ArgumentException("The value was of an unsupported type", "aValue");
}

Готово!

0 голосов
/ 24 февраля 2012

У вас там 2 этапа ... Сначала вы проверяете все, а затем aValue отдельно.

Итак, отделите его.

Затем вы можете использовать обобщения для вызоваспециальная функция для типа aValue

void foo<T> (T aValue) where T : struct { } //value type

void foo<T> (List<T> aValue) where T : struct { } //List of value type

void foo<T> (T[] aValue) where T : struct { } //Array of value type

Если вы хотите лучшее ограничение для числовых типов: Общее ограничение для соответствия числовых типов

0 голосов
/ 24 февраля 2012

Просто заставьте его принять double[]. Позвольте вызывающему коду втиснуть свои данные в правильный формат или предоставьте перегрузки для других типов данных.

Например, если ваш метод:

public double[] Calculate(double[] aValue, double[] fValue, ...)
{
}

Вы можете предоставить следующие перегрузки:

public double[] Calculate(double aValue, double fValue, ...)
{
    return Calculate(new double[]{aValue}, new double[]{fValue}, ...);
}

public double[] Calculate(IEnumerable<double> aValue, IEnumerable<double> fValue, ...)
{
    return Calculate(aValue.ToArray(), fValue.ToArray(), ...);
}

Чтобы охватить другие типы данных, вы можете уменьшить количество перегрузок, используя что-то вроде:

public double[] Calculate<T>(T aValue, T fValue) where T : IConvertible
{
    return Calculate(aValue.ToDouble(), fValue.ToDouble(), ...);
}

public double[] Calculate<T>(IEnumerable<T> aValue, IEnumerable<T> fValue) where T : IConvertible
{
    return Calculate(aValue.Select(x=>x.ToDouble()), fValue.Select(x=>x.ToDouble()), ...);
}

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

Если вы сделаете это, код в вашем методе расчета уменьшится до:

public double[] Calculate(double[] aValue, double[] fValue, int numData, int numPts)
{
    if (numData < 2) throw new ArgumentOutOfRangeException("numberData must be >= 2.");
    if (numPts < 2) throw new ArgumentOutOfRangeException("numberPoints must be >= 2.");
    if (numData < numPts) throw new ArgumentOutOfRangeException("numberData must be
    >= numPts.");

    // do calculation
}

... что намного проще.

0 голосов
/ 24 февраля 2012

Я думаю, что куча перегрузок была бы подходящим вариантом.Каждый из них будет довольно простым, просто вызывая основной метод.Но тогда все ваше тестирование типов данных выполняется компилятором, а не вашими огромными операторами if.Вы также можете установить флаг в каждой перегрузке, чтобы сообщить вашему методу main, получили ли вы одно число, List <> или массив (или что-то еще, что вам нужно обработать).Например:

enum DataType { SingleNumber, NumberList, NumberArray }

// one of many overloads
public static double[] MyMethod(int numPts, int numData, byte aValue, object fValue) {
  return MyMethod(numPts, numData, (object)aValue, fValue, DataType.SingleNumber);
}
0 голосов
/ 24 февраля 2012

Вы на самом деле не хотите этого делать.

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

...