使用扩展方法检查值是否为0

时间:2018-05-16 13:36:40

标签: c#

我有一个类似

的扩展方法
public static T ThrowIfObjectIsNull<T>(this T argument) where T : class
{
  if (argument == null)
      throw new ArgumentNullException(nameof(argument));

   return argument;
}

这基本上检查传递的对象是否为空。我想要做的是创建另一个扩展方法,其中传入的int值不是0.所以我继续创建:

public static T ThrowIfZero<T>(this T argument) where T : struct
{
   if (argument == 0)
     throw new ArgumentOutOfRangeException("some error here");

   return argument;
}

当然上面没有编译提示错误:

  

错误CS0019运算符'=='无法应用于'T'和'int'类型的操作数

有人能指出我如何检查参数值是否不是0的正确方向吗?

5 个答案:

答案 0 :(得分:23)

您可以简单地使用Equals

public static T ThrowIfZero<T>(this T argument) where T : struct
{
    if (argument.Equals(0))
        throw new ArgumentOutOfRangeException("some error here");

    return argument;
}

但如果参数是例如十进制0.0m并且不等于Peter已正确评论的整数0,那么这将无法正常工作。

因此,如果您想要一个适用于任何数字的版本,您可以使用此方法:

public static T ThrowIfZero<T>(this T argument) where T : struct
{
    bool isZero = Decimal.Compare(0.0m, Convert.ToDecimal(argument)) == 0;
    if (isZero)
        throw new ArgumentOutOfRangeException("some error here");

    return argument;
}

答案 1 :(得分:12)

您也可以使用EqualityComparer

public static T ThrowIfZero<T>(this T argument) where T : struct
{   
     if (EqualityComparer<T>.Default.Equals(argument, default(T)))   
        throw new ArgumentOutOfRangeException("some error here");

     return argument;
}

你可以参考这个post的答案(信用证应该转到@Mehrdad)。

答案 2 :(得分:4)

看起来你根本不需要泛型。如果变量只是你建议的int,只需使用:

public static int ThrowIfZero(this int argument)
{
    if (argument == 0)
    {
        throw new ArgumentOutOfRangeException("some error here");
    }

    return argument;
}

答案 3 :(得分:1)

intdecimal等实施IComparable,所以这样的事情也有效:

public static T ThrowIfZero<T>(this T argument) 
    where T : struct, IComparable
{
   if (argument.CompareTo(default(T)) == 0)
     throw new ArgumentOutOfRangeException("some error here");

   return argument;
}

答案 4 :(得分:0)

我最近看到的另一种方式:

public static int ThrowIfZero<T>(this T param)
    where T : struct
{
    var o = (object)param;
    int i;

    try   { i = (int)o; }
    catch { throw new ArgumentException("Param must be of type int");  }

    if (i == 0) throw new ArgumentException("Must be not be zero");

    return (int)(object)param;
}

我们可以欺骗编译器让我们先将T转换为int,然后再将其object强制转换为int。这适用于int,但缺点是它仅适用于float,不适用于public static T ThrowIfZero<T>(this T param) where T : struct { switch (param) { case int i: if (i == 0) throwException(); break; case double d: if (d == 0) throwException(); break; case float f: if (f == 0) throwException(); break; case decimal c: if (c == 0) throwException(); break; case long l: if (l == 0) throwException(); break; case uint ui: if (ui == 0) throwException(); break; case ulong ul: if (ul == 0) throwException(); break; case byte b: if (b == 0) throwException(); break; default: throw new ArgumentException("Invalid Type"); } return param; // ---- Local Functions ---- // void throwException() => throw new ArgumentException("Must not be zero"); }

如果您希望它适用于所有可数类型,您可以使用模式匹配并执行以下操作:

where T : numeric

当然,最好的解决方案是,如果他们把Jon Skeet放在他的报价上并做了一个ComplexNumber,它基本上限制了上面的类型,也许是一些自定义类型,所以我们可以包括我们自己的SuperBigIntegerswitch

说实话,我不会这样做,因为第一种方式是铸造,第二种方式只是导致缺失的情况,如果你需要,必须维持NA,只是想到不过,我会展示更多选项。

相关问题