【问题标题】:Self referencing generic member in struct结构中的自引用泛型成员
【发布时间】:2018-04-20 15:20:02
【问题描述】:

我需要加深对使用泛型时如何编译结构的理解。

我有以下代码,它可以工作

public struct TestStruct
{
    public GenericStruct<SecondTestStruct> Header;
    public int TestValue;
}

public struct GenericStruct<T>
{
    public int MessageSize => System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
}

public struct SecondTestStruct
{
    public int TestValue;
}

static void Main(string[] args)
{
    TestStruct test = new TestStruct();
    Console.WriteLine($"Size of test is: {test.Header.MessageSize}");

}

这将打印“测试大小为:4”

但是,如果我更改 TestStruct 以尝试提供自己的大小:

public struct TestStruct
{
    public GenericStruct<TestStruct> Header;
    public int TestValue;
}

我收到运行时错误:System.TypeLoadException: Could not load type 'TestStructGenerics.TestStruct' from assembly.

我猜这与编译器无法创建结构编译时间有关。或者在处理通用解析时可能存在循环引用问题。

编辑:

我刚刚意识到我可以通过将第二种情况更改为:

public struct TestStruct
{
    public GenericStruct<TestStruct> Header => new GenericStruct<TestStruct>();
    public int TestValue;
}

【问题讨论】:

  • 问题是你打算这样做。您的结构包含另一个具有泛型类型 T 的结构,这是第一个包含另一个具有泛型类型 T 的结构的结构,这是第一个包含另一个具有泛型类型 T 的结构的结构,这是第一个包含另一个结构的结构...你知道这是往哪里走吗?您已经创建了一个编译时递归类型定义。编译器本可以足够聪明地检测到这一点,但显然没有,但无论哪种方式,这是什么意思
  • 那个递归定义永远行不通,因为它没有意义。
  • @LasseV.Karlsen 这就是我的想法。我原以为它会给我提供编译时错误,但显然不是。
  • 递归本身并不是一个充分的解释,因为将TestStructGenericStruct 更改为class 可以消除有问题的行为。这是在结构中处理泛型参数的方式所特有的。

标签: c# .net generics


【解决方案1】:

根据 Eric Lippert 在this Roslyn issue 中的 cmets,尚不清楚此问题是否是 CLR 类型加载器限制或此类程序是否无效,如果它们无效,C# 编译器是否应该检测并发出一个错误。实际上,似乎在当局决定之前,无论引入依赖的模式如何,我们都必须避免结构之间的类型循环 - 实例字段(这永远不会工作,因为结构将是无限大小),静态字段,实现的通用接口,或通用参数。可以在编译时通过将循环中的某些结构更改为类来打破这些结构类型循环,或者在运行时通过object 或接口和强制转换来打破这些循环。

另请参阅corresponding CLR issue

【讨论】:

  • 有趣的是,我在解决这个问题时并没有完全偏离主题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-05
相关资源
最近更新 更多