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
}
}
只需让它接受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");
}
完成!