C# 使用T类型参数调用泛型方法

C# 使用T类型参数调用泛型方法,c#,generics,C#,Generics,我正在尝试构建一个方法,该方法将接受各种数值类型,并对它们进行预处理,以获得第二个方法。我不确定是应该简单地重载还是使用泛型方法。我尝试使用泛型方法,但该方法似乎无法识别参数类型。代码如下。有人能给我解释一下,在这种情况下,重载还是使用泛型方法更好?另外,如果我想用一个通用的方法来做这件事,我如何才能让它工作呢?多谢各位 public static class math { public static int nextpow2<T>(T a) {

我正在尝试构建一个方法,该方法将接受各种数值类型,并对它们进行预处理,以获得第二个方法。我不确定是应该简单地重载还是使用泛型方法。我尝试使用泛型方法,但该方法似乎无法识别参数类型。代码如下。有人能给我解释一下,在这种情况下,重载还是使用泛型方法更好?另外,如果我想用一个通用的方法来做这件事,我如何才能让它工作呢?多谢各位

 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;
      }
代码无法编译。我得到以下错误:

nextpow2中出现内部错误:参数a不是数字

有人能解释一下我做错了什么吗?多谢各位

有人能解释一下我做错了什么吗

当然。您正在检查
类型
对象是
sbyte
,还是
字节
,等等。您没有检查类型是否表示
sbyte
等的类型。。。您正在询问该值是否为
sbyte
。从来都不是这样。(这就是为什么会出现编译时错误。)

您可以使用:

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

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));
}
和执行时间异常

此外,类和方法名称都违反了正常的.NET命名约定

有人能解释一下我做错了什么吗

当然。您正在检查
类型
对象是
sbyte
,还是
字节
,等等。您没有检查类型是否表示
sbyte
等的类型。。。您正在询问该值是否为
sbyte
。从来都不是这样。(这就是为什么会出现编译时错误。)

您可以使用:

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

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));
}
和执行时间异常

此外,您的类和方法名称都违反了正常的.NET命名约定。

您可以说

a is sbyte
或者说

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

比一般方法更好的解决方案是:

public static int Nextpow2(double a)
{
    ...
}
除了
decimal
之外的所有numeric类型都可以隐式转换为
double
。因此,使用上述签名,您可以按照自己的方式使用它:

int indx = 0;
int p = math.Nextpow2(indx);
你可以说

a is sbyte
或者说

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

比一般方法更好的解决方案是:

public static int Nextpow2(double a)
{
    ...
}
除了
decimal
之外的所有numeric类型都可以隐式转换为
double
。因此,使用上述签名,您可以按照自己的方式使用它:

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


为什么不直接使用非通用签名
nextpow2(双a)
?您想要支持的许多类型已经隐式转换为
双精度
。如果有人将我的十进制数也更改为双精度,我会非常不高兴。我正在尝试创建一个通用方法。可能有人会传入一个没有隐式转换为双精度的参数,我想抓住这种情况。非常简单关于将十进制转换为双精度的观点很好。谢谢。即使您同时编写了方法及其调用代码,最好的做法是假设调用方使用该方法时不知道其内部实现。在这种情况下,该方法很难使用,因为它对其输入施加了未知规则。如果您希望该方法运行在
double
上设置参数类型
double
,让调用者担心输入是否合适。为什么不使用非通用签名
nextpow2(双a)
?您想要支持的许多类型已经隐式转换为
双精度
。如果有人将我的十进制数也更改为双精度,我会非常不高兴。我正在尝试创建一个通用方法。可能有人会传入一个没有隐式转换为双精度的参数,我想抓住这种情况。非常简单关于将十进制转换为双精度的观点很好。谢谢。即使您同时编写了方法及其调用代码,最好的做法是假设调用方使用该方法时不知道其内部实现。在这种情况下,该方法很难使用,因为它对其输入施加了未知规则。如果您希望该方法运行在
double
上,将参数类型设置为
double
,让调用者担心输入是否合适。Duh。这是完全有道理的。我不知道我怎么会错过这一个。我可以问一下为什么你不会这样做吗?如果你想走“通用数学”的路线,也推荐使用:Skeet的“杂项实用程序库”(还有马克,对吗,乔恩?):@PBrenek:你真的没有编写一个正常意义上的泛型方法。它并不是真的可以处理任何类型,也不是说你要将该值作为该类型的值来处理-你所做的只是调用
Convert.ChangeType
。你认为使它泛型有什么好处?@Jonsket:你缺少了一个返回类型!O_O;p@Jons