C#方法重载

本文关键字:重载 方法 | 更新日期: 2023-09-27 18:25:41

我有一个方法,需要允许各种各样的输入类型。有两类参数:边界类型参数和实际数据输入参数。

例如,边界参数包括顺序、频率、点数和数据点数。这些边界参数的类型为int,无论实际的数据输入参数类型如何,都是常见的。

实际输入参数的类型可能有:byte、int、short、uint、float、double、decimal、long等。更为复杂的是,实际输入数据可能是单个数据,也可能是该类型的列表或数组。因此,实际的输入可能是List或uint[]等。这个输入最终被转换为double类型——要么是single-data,要么是double[]。

该方法由三部分组成:第一部分检查边界参数的有效性。此部分始终应用实际输入数据类型的regardles。第二部分检查并处理输入数据参数。此部分根据输入数据的类型而变化。第三部分对数据进行计算,再次成为常见内容。

我考虑过泛型,也考虑过使用泛型的标准重载,但两者似乎都没有效率。我已经提出了一个我认为可行的解决方案,但我很感激你的评论:我的方法在计算上有效吗?有更好的方法吗。如有意见,不胜感激。

这就是我目前拥有的:

// ... 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
    }
}

C#方法重载

只需让它接受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
}

这要简单得多。

你真的不想这么做。

由于您的输入非常复杂,并且有很多检查,因此您应该将所有输入放入一个负责所有检查的类中。各种类型的输入只是乞求成为派生类。

我认为应该采用一堆重载。每一个都相当简单,只需调用main方法即可。但是,所有的数据类型测试都是由编译器完成的,而不是由庞大的if语句完成的。您还可以在每个重载中设置一个标志,告诉您的主方法,如果您收到一个数字,即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);
}

您有两个阶段。。。首先检查所有内容,然后分别检查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

如果您想为数字类型提供更好的约束:与数字类型匹配的泛型约束

如果您不想要求调用者将其数据转换为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
}

完成!

这是一个实现,尽管毫无疑问还有一个更强大和/或更高效的实现:

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

完成!