浏览模式: 标准 | 列表

在某些情况下,我们需要判断一个标量是否为数字类型,而不仅仅是这个标量是否看上去像个数字,例如:

Perl代码
 
  1. my $val = 123;  
$val 是一个数字,而

Perl代码
 
  1. my $val = "123";  
这个 $val 只是像一个数字。

虽然大部分情况下我们不需要对它们区分的这么清楚,但是总会遇到不得不区分它们的情况,例如当你对它进行序列化操作时,如果只是按照像数字来进行判断,序列化之后的结果则不够准确。当然需要区分它们的情况还有很多,我们这里不做列举。我们下面重点来讲一下怎么区分它们。

在 Perl 5.14 之后的版本中,我们可以通过 & 运算符来做区分:

Perl代码
 
  1. sub isnumeric {  
  2.     my $val = shift;  
  3.     return lengthdo { no warnings "numeric"$val & "" } ) > 0;  
  4. }  
这段代码在 5.14 及其之后的版本上工作的很好,但是在 5.14 之前的版本上它返回的结果却是错误的。

经过各种尝试之后,我们最后终于找到了一种更加简单且在各个版本上都有效的测试方式:

Perl代码
 
  1. sub isnumeric {  
  2.     my $val = shift;  
  3.     ($val ^ $val) eq '0';  
  4. }  
原理是字符串做^运算,结果为空字符串,数字做^运算,结果为0。

因为C#中没有提供 Switch on Type 的功能,因此要判断类型通常会用一长串的if else,当然这种写法的问题是不够高效,且不够美观。因此 C# 中对常见类型提供了一组枚举值,也就是 TypeCode(这个枚举类型在.NET for Windows App Store 中居然被取消了,大概是因为DBNull这个类型本身也被取消了,这个值没有对应的类型了,干脆连TypeCode就一起取消了)。可以使用 Type.GetTypeCode 方法来得到类型对应的枚举值,之后对得到的枚举值进行switch操作。但需要注意这里有一组特殊的类型,那就是枚举类型,它的返回值是该枚举类型对应的数字类型,而不是Object类型。

因此如果你想区分枚举类型和数字类型的话,记住不要直接用这个方法,至少要先用 IsEnum 来判断一下。否则你可能会错把枚举了类型当成数字类型进行处理。

1月
03

C# 中 is 和数组的问题

在C#中,我们可以很方便的在object对象上使用is运算符来快速的判断对象的类型,is运算符还具有在子类对象上判断是否属于某个父类或者接口的能力,与之等价的判断是,使用GetType方法获得类型后,使用父类或接口上的IsAssignableFrom方法来判断。后者速度比使用 is 运算符要慢很多。所以通常我们在存在对象和已知要判断的类型时优先使用is运算符。

但是is运算符在判断数组类型时却有一个bug,当然这个bug也许是设计问题,但是它确实可能跟我们期望的行为不一致。

这个bug可以这样描述,当一个整数数组对象(byte[], sbyte[], short[], ushort[], int[], uint[], long[], unlong[]这八种)被赋值给一个object对象时,在这个object对象上使用is方法判断时,在等位长整数类型上判断的结果总为True,与类型是否有符号无关。例如:

C#代码
 
  1. int[] a = new int[] { -3, -2, -1, 0, 1, 2, 3 };  
  2. Console.WriteLine(a is int[]);  
  3. Console.WriteLine(a is uint[]);  
  4. object o = a;  
  5. Console.WriteLine(o is int[]);  
  6. Console.WriteLine(o is uint[]);  
的输出结果为:

True
False
True
True

前三个输出是我们期望的,但是最后一个输出的True却是出乎意料的。

这里如果把 int[] a 换成 uint[] a 也是一样,例如:

C#代码
 
  1. uint[] a2 = new uint[] { 0, 1, 2, 3 };  
  2. Console.WriteLine(a2 is int[]);  
  3. Console.WriteLine(a2 is uint[]);  
  4. o = a2;  
  5. Console.WriteLine(o is int[]);  
  6. Console.WriteLine(o is uint[]);  
的输出结果是:

False
True
True
True

第三个输出结果True是我们意料之外的。

同样byte[]和sbyte[]也存在这种关系,short[]和ushort[],long[]和ulong[]之间同样也存在这种关系。

所以使用is在这几种数组的object对象上做判断时,一定要注意这个问题,否则很容易掉进这个陷阱中去。