C# 为什么泛型类中具有重复嵌套类型的字段声明会导致源代码大量增加?
这种情况非常罕见,但非常简单:定义一个泛型类,然后创建一个从外部类继承的嵌套类,并在嵌套类中定义一个关联字段(自类型)。代码段比描述更简单:C# 为什么泛型类中具有重复嵌套类型的字段声明会导致源代码大量增加?,c#,.net,c#-4.0,generics,nested,C#,.net,C# 4.0,Generics,Nested,这种情况非常罕见,但非常简单:定义一个泛型类,然后创建一个从外部类继承的嵌套类,并在嵌套类中定义一个关联字段(自类型)。代码段比描述更简单: class Outer<T> { class Inner : Outer<Inner> { Inner field; } } 反编译后,此字段将如下所示: internal class Outer<T> { private class Inner : Outer<O
class Outer<T>
{
class Inner : Outer<Inner>
{
Inner field;
}
}
反编译后,此字段将如下所示:
internal class Outer<T>
{
private class Inner : Outer<Outer<T>.Inner>
{
private Outer<Outer<T>.Inner>.Inner field;
}
}
private Outer<Outer<Outer<T>.Inner>.Inner>.Inner field;
最后,本课程:
class X<A, B, C, D, E>
{
class Y : X<Y, Y, Y, Y, Y>
{
Y.Y.Y.Y.Y.Y.Y.Y.Y y;
}
}
X类
{
Y类:X类
{
Y.Y.Y.Y.Y.Y.Y.Y.Y;
}
}
结果为27.9MB(29302272字节)
汇编和总生成时间:00:43.619
使用的工具
编译是在C#5和C#4编译器下完成的。反编译由dotPeek完成。生成配置:
Release
和Debug
从使用当前类型参数化的泛型继承通常会被调用,并且不鼓励使用
在您的例子中,嵌套类Outer.internal
定义为从Outer
继承。这意味着嵌套类通过继承包含嵌套类的定义。这将产生嵌套类的无限定义:Outer.Inner.Inner.Inner…
现在,按照你最初的定义
class Inner : Outer<Inner>
{
Inner field;
}
回到你的问题上来:
我们为什么要观察这种行为?内部。内部类型声明是否已更改类型?在这种情况下,内部类型和内部类型在某种程度上是不同的吗
您更改了类内部的类型定义,使其字段的类型不同。Outer.internal
的实例可能(我还没有验证)可以强制转换到另一个内部类型,但它们是两个类型定义。这不是答案
你的问题有很多方面。一个小问题是:如果一个类型包含一个与该类型本身同名的嵌套类型(因为继承,否则是不允许的),并且如果该名称在该类型中使用,那么该名称指的是什么
这很难用语言表达,但我想举个例子:
namespace N
{
class Mammal
{
// contains nested type of an unfortunate name
internal interface Giraffe
{
}
}
class Giraffe : Mammal
{
Giraffe g; // what's the fully qualified name of the type of g?
}
}
注意:这很简单!没有仿制药!类继承自己的包含类没有问题
这里的问题是,
g
的类型是什么?它是N.Giraffe
(一个类),还是N.Giraffe.Giraffe
(一个接口)?正确答案是后者。因为要找到名称Giraffe
的含义,首先要搜索当前类型的成员(在本例中,要找到接口)。只有在没有找到匹配项的情况下,才会转到当前名称空间的成员(可以在其中找到当前类型)。问题的核心是为什么Inner。Inner
与Inner
是不同的类型。一旦您了解了这一点,您对编译时和生成的IL代码大小的观察就很容易理解了
首先要注意的是,当你有这个声明
public class X<T>
{
public class Y { }
}
有无数种方法可以引用嵌套类型B
。一个是A.B
,另一个是A.B.B
,依此类推。语句typeof(A.B)==typeof(A.B.B)
返回true
当你把这两者结合在一起,你所做的方式,一些有趣的事情发生了。类型Outer.Inner
与Outer.Inner.Inner
的类型不同Outer.Inner
是Outer
的一个子类,而Outer.Inner.Inner
是Outer
的一个子类,我们之前建立的它不同于Outer.Inner
。所以Outer.Inner.Inner
和Outer.Inner
是指不同的类型
生成IL时,编译器始终使用类型的完全限定名。您已经聪明地找到了一种方法来引用名称长度以指数速度增长的类型。这就是为什么当你增加
外部
的通用算术,或者在内部
的字段
中添加额外的.Y
级别时,输出IL大小和编译时间增长得如此之快。你是在调试还是发布中编译的?@Tigran:调试和发布的结果都是一样的。而你的观察结果是一样的有趣的是,你的问题有点像“为什么n^n
增长如此之快?”。+1,可怕的泛型滥用。这确实是可怕的泛型滥用!我完全打算在我的博客上偷取这个例子。如果你对这类事情感兴趣,你可能会发现两篇文章很有趣:和它的字段是不同类型的你能说明原因吗?很难理解为什么通过继承访问会以某种方式改变inselfYou中的静态类型:“该字段被声明为typeinternal
,在这个范围中它指的是正在定义的当前类型”实际上,我认为这不正确。我可以提供另一个例子。我认为此范围内的internal
对应于名为internal
的继承成员。我在答案中添加了一个示例,以显示classI的扩展定义。我提交了一个答案,这实际上只是试图解释我上面第一条评论的意思。感谢回复,在玩了不同的配置之后,我终于了解了这种情况。谢谢你的帮助。如果你不介意的话,我会接受迈克的回答,因为他更深入了一点。(尽管很难选择)你的分析是正确的;“是一种”关系是一种比“是我容器的一员”关系更为“密切”的关系。在我看来,我终于抓住了这个领域不同声明之间的差距。谢谢你的帮助。
//original
class Outer<A>
{
class Inner1 //: Outer<Inner1>
{
Inner1 field;
//from inheritance
class Inner2 : Outer<Inner1.Inner2>
{
Inner2 field;
}
}
}
//modified for Inner.Inner
class Outer<A>
{
class Inner1 //: Outer<Inner1>
{
Inner1.Inner2 field;
//from inheritance
class Inner2 : Outer<Inner1.Inner2>
{
Inner2.Inner3 field;
}
}
}
namespace N
{
class Mammal
{
// contains nested type of an unfortunate name
internal interface Giraffe
{
}
}
class Giraffe : Mammal
{
Giraffe g; // what's the fully qualified name of the type of g?
}
}
public class X<T>
{
public class Y { }
}
public class A
{
public class B : A { }
}