不从 System.Object 继承之后
Written by Allen Lee
上一篇文章说到 IL 允许创建一个不继承自 System.Object 的类,这打破了我们已有的一些认识。到了这个份上,我们自然会追问,为什么要允许这种类型存在呢?
考察如下 C++/CLI 代码:
1
using namespace System;
2![](/Images/OutliningIndicators/None.gif)
3
public ref class Person
4
{
5
public:
6
Person(String^ name)
7
{
8
m_Name = name;
9
}
10![](/Images/OutliningIndicators/InBlock.gif)
11
Person(Person% p)
12
{
13
m_Name = p.Name;
14
}
15![](/Images/OutliningIndicators/InBlock.gif)
16
property String^ Name
17
{
18
String^ get()
19
{
20
return m_Name;
21
}
22
}
23![](/Images/OutliningIndicators/InBlock.gif)
24
private:
25
String^ m_Name;
26
};
27![](/Images/OutliningIndicators/None.gif)
28
void DisplayPersonInfo(Person p)
29
{
30
Console::WriteLine("Name: {0}", p.Name);
31
}
32![](/Images/OutliningIndicators/None.gif)
33
int main(array<System::String ^> ^args)
34
{
35
Person^ p = gcnew Person("Allen");
36
DisplayPersonInfo(*p);
37![](/Images/OutliningIndicators/InBlock.gif)
38
return 0;
39
}
![](/Images/OutliningIndicators/None.gif)
2
![](/Images/OutliningIndicators/None.gif)
3
![](/Images/OutliningIndicators/None.gif)
4
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
5
![](/Images/OutliningIndicators/InBlock.gif)
6
![](/Images/OutliningIndicators/InBlock.gif)
7
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
8
![](/Images/OutliningIndicators/InBlock.gif)
9
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
10
![](/Images/OutliningIndicators/InBlock.gif)
11
![](/Images/OutliningIndicators/InBlock.gif)
12
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
13
![](/Images/OutliningIndicators/InBlock.gif)
14
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
15
![](/Images/OutliningIndicators/InBlock.gif)
16
![](/Images/OutliningIndicators/InBlock.gif)
17
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
18
![](/Images/OutliningIndicators/InBlock.gif)
19
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
20
![](/Images/OutliningIndicators/InBlock.gif)
21
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
22
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
23
![](/Images/OutliningIndicators/InBlock.gif)
24
![](/Images/OutliningIndicators/InBlock.gif)
25
![](/Images/OutliningIndicators/InBlock.gif)
26
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
27
![](/Images/OutliningIndicators/None.gif)
28
![](/Images/OutliningIndicators/None.gif)
29
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
30
![](/Images/OutliningIndicators/InBlock.gif)
31
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
32
![](/Images/OutliningIndicators/None.gif)
33
![](/Images/OutliningIndicators/None.gif)
34
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
35
![](/Images/OutliningIndicators/InBlock.gif)
36
![](/Images/OutliningIndicators/InBlock.gif)
37
![](/Images/OutliningIndicators/InBlock.gif)
38
![](/Images/OutliningIndicators/InBlock.gif)
39
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
DisplayPersonInfo 方法只能用在 C++/CLI 中,你无法在 C# 中对引用类型进行解引用,就像第三十六行那样。为了处理 C++/CLI 的特性,IL 引入了不少别的语言无法使用的东西。
或许,如同部分评论所言,此举乃是为某些语言的特性埋下伏笔。然而,此举却为 C# 带来了麻烦。我用上一篇文章里所说的方法创建了一个不继承自 System.Object 的 NoInherit 类,置于 NoInherit.dll 中,然后用 Visual Studio 2005 新建一个项目,引用 NoInherit.dll,并在 Main 里写下这些代码:
1
Type t = typeof(NoInherit);
2
Console.WriteLine(t.BaseType == null);
3![](/Images/OutliningIndicators/None.gif)
4
NoInherit ni = new NoInherit("NoInherit");
5
object o = ni as object;
6
if (o != null)
7
{
8
Console.WriteLine(o.GetType());
9
Console.WriteLine(o.ToString());
10
}
![](/Images/OutliningIndicators/None.gif)
2
![](/Images/OutliningIndicators/None.gif)
3
![](/Images/OutliningIndicators/None.gif)
4
![](/Images/OutliningIndicators/None.gif)
5
![](/Images/OutliningIndicators/None.gif)
6
![](/Images/OutliningIndicators/None.gif)
7
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
8
![](/Images/OutliningIndicators/InBlock.gif)
9
![](/Images/OutliningIndicators/InBlock.gif)
10
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
你猜上面代码的运行结果是什么?正常来说,运行结果应该只有一个 true,即第二行的输出,但事实上,第八行居然正确输出“NoInherit”,而第九行则抛出 AccessViolationException。按道理,第九行的异常是意料中事,但第二行和第五行的结果就很矛盾了。第二行输出 true 表明了 NoInherit 类的确没有继承自 System.Object,但第五行却转换成功,否则 o 应该是 null 的。
当一个系统复杂到一定程度,一个看似没问题的改动可能会导致一些看似不相关的问题。当你拿到一个库时,你是假定里面的所有类都继承自 System.Object,还是去验证一下呢?