是否可以仅使用值类型创建参考周期?

时间:2010-09-04 04:52:39

标签: .net serialization struct reference value-type

作为解释,请在C#中使用此值类型:

struct ObjRef
{
    public object Value;
    public ObjRef(object value) { Value = value; }
}

我可以想象一个对象图,其中有两个盒装这种类型的实例,每个实例都包含对另一个的引用。这就是我所说的只有值类型的参考周期。

我的问题是这样的对象图是否可以在.NET中构建。从概念上讲,如果存在,构造将是这样的:

object left = new ObjRef();
object right = new ObjRef(left);
left.Value = right;

但显然,最后一行没有有效的C#。最后一行:

((ObjRef)left).Value = right;

没有达到结果,因为强制转换展开left并最终改变副本。所以至少在直接的C#中,它看起来不像是可能的。

是否有人知道是否可以使用反射,不安全代码,dynamic,IL代码或任何其他方式实现构造?或者,任何人都可以证明CLR有效地阻止了这样的参考周期吗?

请注意,我实际上并不想创建这样的对象图。相反,答案可能会影响使用对象图的算法设计,例如序列化/反序列化格式化程序。


修改

正如Brian 建议的那样,确实可以通过将其转换为接口类型而不是值类型来修改盒装值而不将其取消装箱。所以给出了这段代码:

interface IObjRef
{
    IObjRef Value { get; set; }
}

struct ObjRef : IObjRef
{
    IObjRef value;
    public IObjRef Value { get { return value; } set { this.value = value; } }
    public ObjRef(IObjRef value) { this.value = value; }
}

然后我描述的参考周期可以这样构造:

IObjRef left = new ObjRef();
IObjRef right = new ObjRef(left);
left.Value = right;

这基本上让我们理性#72为什么可变的价值类型是邪恶的。

3 个答案:

答案 0 :(得分:2)

这可以通过使用接口并使值类型实现接口并相互引用来实现。这允许它们通过盒装值创建循环,因为与接口引用一起使用时的结构将被加框。

快速示例

interface ICycle
{
    void SetOther(ICycle other);
}

struct Cycle : ICycle
{
    ICycle value;
    public void SetOther(ICycle other)
    {
        value = other;
    }
}

class Example
{
    static void CreateCycle()
    {
        ICycle left = new Cycle();   // Left is now boxed
        ICycle right = new Cycle();  // Right is now boxed
        left.SetOther(right);
        right.SetOther(left);  // Cycle
    }
}

我分享Brian的问题,但想知道这会给你带来什么好处。

答案 1 :(得分:1)

老实说,我还没有尝试过,但看看是否有Value属性在界面上,然后使用界面作为你的盒子让你改变盒装本身而不是新副本。

我隐约觉得这是可能的,虽然我不确定为什么我这么想。有帮助,嗯?

答案 2 :(得分:0)

我不知道结构可以实现接口。这看起来很奇怪;有什么好处?对于一般的结构,还是对具有作用于它们的属性和方法的结构,是不喜欢?它太糟糕了.net不允许将某些结构属性和方法声明为mutators,它们在“ReadOnly”结构上的使用将被禁止。