C# 在不使用';不存在

C# 在不使用';不存在,c#,constructor,struct,member,cyclic-reference,C#,Constructor,Struct,Member,Cyclic Reference,这是我的一些代码的简化版本: public struct info { public float a, b; public info? c; public info(float a, float b, info? c = null) { this.a = a; this.b = b; this.c = c; } } 问题是错误Struct成员“info”导致结构布局中出现循环。I关注类似Struct的值类

这是我的一些代码的简化版本:

public struct info
{
    public float a, b;
    public info? c;

    public info(float a, float b, info? c = null)
    {
        this.a = a;
        this.b = b;
        this.c = c;
    }
}
问题是错误
Struct成员“info”导致结构布局中出现循环。
I关注类似Struct的值类型行为。我可以使用一个类和一个克隆成员函数来模拟它,但我不明白为什么我需要这样做

这个错误怎么是真的?在某些类似的情况下,递归可能会导致永久性的构造,但在这种情况下,我想不出任何可能的方法。下面是一些示例,如果程序能够编译,这些示例应该是很好的

new info(1, 2);
new info(1, 2, null);
new info(1, 2, new info(3, 4));
编辑:

我使用的解决方案是使“info”成为一个类而不是一个结构,并给它一个成员函数,以返回我在传递它时使用的副本。实际上,模拟与结构相同的行为,但使用类

在寻找答案的同时,我还提出了以下问题


这会创建一个循环的原因是
Nullable
本身就是一个
struct
。因为它引用了
info
,所以布局中有一个循环(
info
的字段为
null
,字段为
info
)。它本质上等同于以下内容

public struct MyNullable<T> {
  public T value;
  public bool hasValue;
}

struct info { 
  public float a, b;
  public MyNullable<info> next;
}
公共结构MyNullable{
公共价值观;
公共价值观;
}
结构信息{
公众浮标a、b;
公共MyNullable next;
}

真正的问题在于这一行:

public info? c;
由于这是一个
结构
,C#需要知道内部的
信息
/s布局,然后才能生成外部的
信息
布局。并且内部
info
包括内部
info
,其依次包括内部
info
,以此类推。由于此循环引用问题,编译器无法生成布局


注意:
info?c
Nullable
的简写,它本身就是一个
struct
将自身作为成员的struct是不合法的。这是因为结构具有固定大小,并且它必须至少与其每个成员的大小之和一样大。对于两个浮点数,您的类型必须有8个字节,至少一个字节显示
info
是否为空,加上另一个
info
的大小。这就产生了以下不等式:

 size of info >= 4 + 4 + 1 + size of info
这显然是不可能的,因为它需要你的字体无限大


您必须使用引用类型(即类)。您可以使类不可变,并覆盖
Equals
GetHashCode
以提供类似值的行为,类似于
字符串
类。

没有任何方法可以实现可变大小项的可变值语义(从语义上讲,我认为您所追求的是让
MyInfo1=MyInfo2
生成一个新的链表,该链表从MyInfo2启动的链表中分离出来)。可以用
info[]
替换
info?
(该链表将始终为null,或者使用单个元素数组填充),或使用包装了
info
实例的holder类,但语义可能不是您想要的。在
MyInfo1=MyInfo2
之后,对
MyInfo1.a
的更改不会影响
MyInfo2.a
,对
MyInfo1.c
的更改也不会影响
MyInfo2.c
,而是对
MyInfo>的更改1.c[0]。a
将影响MyInfo2.c[0]。a

如果将来的.net版本能够有一些“值引用”的概念,那就太好了.NET不能支持C++复制构造函数的所有复杂之处,但是在允许“结构”类型的存储位置具有与存储位置而不是其内容相关联的标识时,也有价值。> 鉴于.net目前不支持任何此类概念,但是,如果您希望
info
是可变的,您必须要么忍受可变引用语义(包括保护性克隆)或者使用古怪的结构类混合语义。如果性能是一个问题,我的一个建议是使用一个抽象的
InfoBase
类,其子体
MutableInfo
ImmutableInfo
,成员如下:

  • AsNewFullyMutable
    ——公共实例——返回一个新的
    MutableInfo
    对象,其中包含从原始对象复制的数据,在任何嵌套引用上调用
    AsNewFullyMutable

  • AsNewMutable
    --公共实例--返回一个新的
    MutableInfo
    对象,其中包含从原始对象复制的数据,对任何嵌套引用调用
    AsImmutable

  • AsNewImmutable
    ——受保护的实例——返回一个新的
    ImmutableInfo
    对象,其中包含从原始文件复制的数据,对任何嵌套引用调用
    AsImmutable
    (而不是
    AsNewImmutable

  • AsImmutable
    ——Public virtual——对于
    ImmutableInfo
    ,返回自身;对于
    MutableInfo
    ,在自身上调用
    AsNewImmutable

  • AsMutable
    ——Public virtual——对于
    MutableInfo
    ,返回自身;对于
    ImmutableInfo
    ,在自身上调用
    AsNewMutable


  • 克隆对象时,根据是否希望在对象发生变异之前再次克隆该对象或其后代,可以调用
    AsImmutable
    AsNewFullyMutable
    ,或
    AsNewMutable
    。在希望对象被反复防御性克隆的场景中,object将被一个不可变的实例所取代,而该实例将不再需要克隆,直到有人希望对其进行变异。

    免责声明:这可能无法实现“struc”的目标
    public struct info
    {
        public float a, b;
        public info? c
        {
            get
            {
                return cArray[nextIndex];
            }
            set
            {
                steps[nextIndex] = value;
            }
        }
        private info?[] cArray;
    
        public info(float a, float b, info? c = null)
        {
            this.a = a;
            this.b = b;
            this.cArray = new info?[] { c }
            this.c = c;
        }
    }