如果我实现了一个可能有大量类型参数实例化的泛型类型,我应该避免(对于JIT性能/代码大小等原因)有许多嵌套的非泛型类型吗?
示例:
public class MyGenericType<TKey, TValue>
{
private struct IndexThing
{
int row; int col;
}
private struct SomeOtherHelper
{
..
}
private struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>> { }
}
同样有效的替代方法是在外部使用非泛型类型,但随后它们会污染命名空间。 有最好的做法吗?
public class MyGenericType<TKey, TValue>
{
private struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>> { }
}
internal struct IndexThingForMyGenericType
{
int row; int col;
}
internal struct SomeOtherHelper
{
...
}
答案 0 :(得分:6)
在C#中,泛型类型的每个嵌套类型本质上都是通用的。编译器也会将嵌套类型设置为通用类型(我们不知道)。有关详细信息,请参阅this article。
虽然泛型共享引用类型的JIT代码,如this interview中所述,但与非泛型类相比,它有一些开销。每种值类型都有自己的JIT代码。
如果类型仅在泛型类中使用 - 作为私有嵌套类型更有意义。
如果在其他地方使用该类型,那么理想情况下它应该是非嵌套类型(作为内部类型)。
也就是说,如果您的嵌套类型在这种情况下不使用类型参数T
,则它不需要是泛型类型的嵌套类型,因此它也成为泛型类型。 / p>
大多数情况下它应该无关紧要但是如果您关注在运行时创建的许多类型,您可以重构您的泛型类型以具有非泛型基类,该基类充当嵌套类型的容器类型并公开嵌套类型为protected。
public class NonGenericBase
{
protected struct IndexThing
{
int row; int col;
}
protected struct SomeOtherHelper
{
..
}
}
public class MyGenericType<TKey, TValue> : NonGenericBase
{
private struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>> { }
}
这样您就可以共享相同的嵌套类型。没有运行时开销。每个类型参数没有单独的类型。现在typeof(MyGenericType<int, string>.SomeOtherHelper)
将等于typeof(MyGenericType<long, bool>.SomeOtherHelper)
。
答案 1 :(得分:1)
虽然这并没有完全回答这个问题,但请注意,对于引用类型,代码是共享的,因为内部它都是关于指针的。因此,您不必担心代码库膨胀。引自this回答(Anders Hejlsberg是引用)。
现在,我们接下来要做的是所有有价值的类型实例化 类型 - 例如
List<int>
,List<long>
,List<double>
,List<float>
- 我们创建可执行本机代码的唯一副本。所以List<int>
得到了 它自己的代码。List<long>
获取自己的代码。List<float>
有自己的 码。 对于所有引用类型,我们共享代码,因为它们是 代表性相同。它只是一个指针。