为什么泛型结构不能具有在C#中指定泛型类型的静态成员? [英] Why can't generic structs have static members which specify the generic type in C#?

查看:78
本文介绍了为什么泛型结构不能具有在C#中指定泛型类型的静态成员?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很抱歉,如果这是重复的!我四处搜寻,但找不到解释.当我尝试实例化此结构时,以下玩具示例将为我提供TypeLoadException.如果我使用一个类,或者在静态成员中不指定泛型类型(将其保留为T),则效果很好.

Apologies if this is a duplicate! I searched around but wasn't able to find an explanation. The following toy example gives me a TypeLoadException as soon as I try to instantiate this struct. It works just fine if I use a class or if instead do not specify the generic type in the static member (leave it as T.)

public struct Point<T>
{
    static Point<int> IntOrigin = new Point<int>(0, 0);

    T X { get; }
    T Y { get; }

    public Point(T x, T y)
    {
        this.X = x;
        this.Y = y;
    }
}

我比较复杂的实际情况归结为这样的事情,所以我真的很想了解为什么它会发出TypeLoadException.

My rather more complicated, real situation boils down to something like this, so I'd really like to understand why it emits a TypeLoadException.

推荐答案

此评论,以及有关Github的另一条评论解决当前的事务状态,指出为什么不允许使用这种自指代结构定义,并且在可预见的将来也不可能.

This comment, and another comment, on Github come closest to addressing the current state of affairs, pointing out why the sort of self-referential struct definition hasn't been allowed, and likely won't be for the foreseeable future.

即使静态成员也需要先初始化类型,然后才能将其包含在类型布局中,但是类型初始化也需要初始化该静态成员.这种初始化依赖关系的循环会创建Catch-22,从而导致运行时异常.

Even the static member needs the type to be initialized before it can be included in the type layout, but the type initialization needs that static member to be initialized. This cycle of initialization dependencies creates the Catch-22 that results in the runtime exception.

根据此评论,.NET Core可以与这种模式.但是,当我在.NET Core项目中尝试您的示例时,我发现了相同的失败.因此,要么该注释有误,要么实例成员方案与静态成员方案之间存在细微差别(我不愿意对此进行任何进一步研究).

According to this comment, .NET Core works fine with this pattern. But I found the same failure when I tried your example in a .NET Core project. So either that comment is in error, or there's some subtle difference between the instance-member scenario and your static-member scenario (I didn't bother to investigate any further than that).

有趣的是,在dotNETFiddle.net上使用的编译器会发出编译时错误, .我不知道为什么Visual Studio编译器似乎不再产生此错误(在2017年和2019年进行了检查).在我看来,好像是另一个错误.但是关于Github的讨论似乎接受了该代码在技术上是有效的(即,根据C#规范),因此可能在某个时候有意识地决定要删除编译器错误,并让CLR进行投诉.运行时.

It is interesting that the compiler used on dotNETFiddle.net emits a compile-time error, "Struct member 'struct2 field' of type 'struct1' causes a cycle in the struct layout". I don't know why the Visual Studio compiler no longer seems to produce this error (checked in 2017 and 2019). It seems like another bug to me. But the discussion on Github around this issue seems to accept that the code is technically valid (i.e. according to the C# specification), so probably there was at some point a conscious decision to remove the compiler error, and let the CLR do the complaining at runtime.

请注意,错误参考页中的建议建议更改为 class ,而不是 struct .当然,在使用 struct 的情况下,这通常是不可行的.值类型可能很重要.但是,在您的特定示例中,实际上有一个基于该想法的简单解决方法.由于您的字段不是 struct instance 的实际布局的一部分,因此您可以将其移到专门用于此类值的静态类中.例如:

Note that the advice in the error's reference page suggests changing to a class instead of a struct. Of course, this is often not feasible where a struct is being used; it may be important to have a value type. However, in your specific example, there's actually a simple work-around based on that idea. Since your field isn't part of the actual layout of an instance of the struct, you can move it to a static class used specifically for such values. E.g.:

public struct Point<T>
{
    public static class Constants
    {
        static Point<int> IntOrigin = new Point<int>(0, 0);
    }

    T X { get; }
    T Y { get; }

    public Point(T x, T y)
    {
        this.X = x;
        this.Y = y;
    }
}

然后,您需要使用 Point< double> .Constants.IntOrigin ,而不是(例如) Point< double> .IntOrigin .由于每种类型的类型初始化都可以独立完成,因此初始化周期不会发生,并且代码可以正常运行.

Then instead of (for example) Point<double>.IntOrigin, you'll need to use Point<double>.Constants.IntOrigin. Since the type initialization for each type can be done independently, the cycle in the initialization does not occur and the code runs fine.

这篇关于为什么泛型结构不能具有在C#中指定泛型类型的静态成员?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆