有一个有趣的古怪 - 以为有人也许能提供帮助。
这冒出来的一些有趣的空类型从这个问题:
如何检查对象是否为空?
Option Strict On
Module Test
' Call this overload 1
<Extension()>
Function IsNullable(obj As ValueType) As Boolean
Return False
End Function
' Call this overload 2
<Extension()>
Function IsNullable(Of T As {Structure})(obj As Nullable(Of T)) As Boolean
Return True
End Function
Sub Test()
' a is an integer!
Dim a As Integer = 123
' calling IsNullable as an extension method calls overload 1 and returns false
Dim result1 As Boolean = a.IsNullable()
' calling IsNullable as method calls overload 2 and returns true
Dim result2 As Boolean = IsNullable(a)
' why? surely the compiler should treat both those calls as equivalent
End Sub
End Module
我预计到ISNULLABLE两个通话将被视为由编译器一样,但事实并非如此。 扩展方法调用使用不同的过载到正常的方法调用,即使参数“a”是不变的。
我的问题是为什么呢? 是什么让编译器改变两个电话之间的心灵?
FTR:我们正在使用Visual Studio 2010,.NET Framework 4中。
我认为这是一个错误,或者至少是VB.NET的“功能”。 (我只是不知道哪个VB.NET或C#的是错误的。)
我曾尝试在LINQPad 4(因为这是我有我使用的机器上)和C#我得到了False
两种结果,对于不同的是每值类型和枚举Nullable
类型,当然。
而对于VB.NET我得到的False
和True
为所有的值类型和枚举,除了Nullable
类型,和ValueType
和[Enum]
这回False
, False
,因为你不能有一个ValueType?
或[Enum]?
。 随着Option Strict Off
, Object
会导致后期绑定,并在运行时查找或者过载会失败,但第二个结果是False
也因为你不能有Object?
。
为了完整起见, Nullable
类型返回True
, True
为这两种语言的预期。
那C#是做一些不同的东西(假设我的测试是正确的),这一事实证实了参考C#“更好的转换”检查是错误的(或者被误读至少 - 在C#是没有做什么解释为为什么VB.NET在做它在做什么)。
不过,我不同意,这个问题可能与隐式转换为Nullable(Of T)
存在,不知何故被更高优先级的隐式转换ValueType
。
这里是我的LINQPad 4 “查询”(C#程序):
void Main()
{
Test.test();
}
// Define other methods and classes here
static class Test
{
static bool IsNullable(this ValueType obj)
{
return false;
}
static bool IsNullable<T>(this T? obj) where T:struct
{
return true;
}
public static void test()
{
int x = 42;
bool result1 = x.IsNullable();
bool result2 = IsNullable(x);
result1.Dump("result1");
result2.Dump("result2");
}
}
过载2只会工作作为明确定义可为空的(T)的的一个扩展。 例如:
Dim y As New Nullable(Of Integer)
y.IsNullable()
这是因为扩展方法扩展的类型(或碱型),在这种情况下是可空(的T)。 调用a.IsNullable()将永远不会调用过载2.这是比较容易的部分弄清楚。 这意味着真正的问题是为什么会超载2被调用,而不是过载1作为标准重载方法调用。
CLR将确定哪些过载到通过执行“使用更好的转换 ”的检查,其中,它隐含转换传递给所述参数(一个或多个)的类型的值(一个或多个)中的过载的方法来定义和然后再往规则清单确定要使用的最佳方法。
从MSDN更好的转换文章:
如果S是T1,C1是更好的转换。
如果S是T2,C2是更好的转换。
Puting此代码到Visual Studio将您显示过载2是更好的转换,因为一个整数(S)是隐式转换可为空的(整数的)一个(T2)的版本。
' a is an integer!
Dim a As Integer = 123
Dim objValueType As ValueType = 123 'Or CType(a, ValueType)
Dim objNullable As Nullable(Of Integer) = 123 'Or CType(a, Nullable(Of Integer))
'Oh No, a compiler error for implicit conversion done for overload 1!
Dim bolValueTypeConversionIsBetter As Boolean = (objValueType = a)
'No error as long as Option Strict is off and it will equal True.
Dim bolNullableConversionIsBetter As Boolean = (objNullable = a)