调用带有T类型参数的泛型方法

本文关键字:泛型方法 类型参数 调用 | 更新日期: 2023-09-27 18:04:57

我试图建立一个方法,将采取各种数字类型和预处理他们的第二个方法。我不确定我是否应该简单地重载或使用泛型方法。我试图使用通用方法,但该方法似乎不识别参数类型。代码如下。有人能向我解释一下,在这种情况下,重载或使用泛型方法是否更好?此外,如果我想使用泛型方法来实现这一点,我该如何使它工作呢?非常感谢。

 public static class math
 {
      public static int nextpow2<T>(T a)
      {
           double w;
           if ( a.GetType() is sbyte   ||
                a.GetType() is byte    ||
                a.GetType() is short   ||
                a.GetType() is ushort  ||
                a.GetType() is int     ||
                a.GetType() is uint    ||
                a.GetType() is long    ||
                a.GetType() is ulong   ||
                a.GetType() is float   ||
                a.GetType() is double  ||
                a.GetType() is decimal
           ) w = (double)Convert.ChangeType(a, typeof(double));
           else
                throw new System.ArgumentException("Internal error in nextpow2: argument a is not a number!");
           return _nextpow2(w);
      }
      private static int _nextpow2(double a)
      {
           double index = Math.Abs(a);
           int p = (index > 1) ? (int)Math.Ceiling( Math.Log( index, 2.0) ) : 0;
           return p;
      }

我调用的方法如下:

 int indx = 0;
 int p = math.nextpow2(indx);

代码编译失败。我得到以下错误:

nextpow2内部错误:参数a不是数字!

谁能解释一下我做错了什么?谢谢你。

调用带有T类型参数的泛型方法

谁能解释一下我做错了什么?

确定。检查Type对象是sbyte还是byte,等等。您没有检查类型是否代表 sbyte等的类型…您询问值是否为sbyte。从来都不是这样的。(这就是为什么你得到一个编译时错误。)

可以使用:

if (a.GetType() == typeof(byte) ||
    // etc)

但我可能不会。我根本不会让它成为泛型方法。如果你真的想要这个功能,我会写:

private static readonly HashSet<Type> ValidTypes = new HashSet<Type>
{
    typeof(sbyte), typeof(byte), /* etc */
};
public static double ConvertToDouble(object x)
{
    if (x == null)
    {
        throw new ArgumentNullException("x");
    }
    if (!ValidTypes.Contains(x.GetType())
    {
        throw new ArgumentException("...");
    }
    return Convert.ChangeType(x, typeof(double));
}

注意这是如何做一件事情:将参数转换为double。让它然后调用_nextpow2是没有意义的——如果调用者想这样做的话,它很容易做到。

另外,你写了两件相互矛盾的事情:

代码编译失败。我得到以下错误:
nextpow2内部错误:参数a不是数字!

如果它编译失败(这是我所期望的,顺便说一句),那么你不能运行代码,这意味着你不能得到异常。您需要区分如下的编译时错误:

warning CS0184: The given expression is never of the provided ('sbyte') type

执行时异常。

而且,你的类名和方法名都违反了正常的。net命名约定。

你也可以说

a is sbyte

a.GetType() == typeof(sbyte)

但将其混合到a.GetType() is sbyte中没有意义。你应该得到一个编译器警告!因为a.GetType()是一个从System.Type派生的对象(实际上是System.RuntimeType),因此它永远不能从sbyte派生(因为sbyte是密封的,是一个结构体,而sbyte本身只从ValueTypeObject派生)。

一个比泛型方法更好的解决方案是:

public static int Nextpow2(double a)
{
    ...
}

decimal外的所有数值类型都可以隐式转换为double。因此,有了上面的签名,你可以按照你想要的方式使用它:

int indx = 0;
int p = math.Nextpow2(indx);