代码之家  ›  专栏  ›  技术社区  ›  Wesley Hill

是否可以仅使用值类型创建引用循环?

  •  5
  • Wesley Hill  · 技术社区  · 14 年前

    为了便于解释,请使用C#中的值类型:

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

    盒装的 此类型的实例,每个实例都持有对另一个实例的引用。这就是我所说的只有值类型的引用循环。

    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;
    

    3 回复  |  直到 7 年前
        1
  •  2
  •   JaredPar    14 年前

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

    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
        }
    }
    

    我和布赖恩一样想知道这会给你带来什么好处。

        2
  •  1
  •   Brian    14 年前

    老实说,我没有试过,但看看有没有 Value 属性在接口上,然后使用接口作为框,可以使框本身而不是新的副本发生变化。

    我隐约觉得这是可能的,尽管我不确定为什么我会这么想。很有用吧?

        3
  •  0
  •   supercat    14 年前