是否可以只使用值类型创建一个引用循环?

时间:2022-03-05 04:16:21

By way of explanation, take this value type in C#:

通过解释,取c#中的这个值类型:

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

I can imagine an object graph where there are two boxed instances of this type, each holding a reference to the other. This is what I mean by a reference-cycle with only value-types.

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

My question is whether or not such an object graph can ever be constructed in .NET. Conceptually, the construction, if it exists, would go like this:

我的问题是在。net中是否可以构造这样的对象图。从概念上讲,如果这个结构存在,它会是这样的:

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

but obviously, the last line there is not valid C#. Making the last line:

但是很明显,最后一行是无效的c#。最后一行:

((ObjRef)left).Value = right;

does not achieve the result as the cast unboxes left and you end up mutating a copy. So at least in straight C#, it doesn't look like the construction is possible.

没有实现的结果,因为施放的开箱离开和你结束突变拷贝。所以至少在c#中,看起来这个结构是不可能的。

Does anybody know if the construction could be achieved using reflection, unsafe code, dynamic, IL code, or in any other manner? Or, can anyone show that the CLR effectively prevents such a reference-cycle?

有人知道这种结构是否可以通过反射、不安全代码、动态代码、IL代码或其他方式实现吗?或者,有人能证明CLR有效地阻止了这样的引用周期吗?

Please note that I don't actually want to create such an object graph. Rather, the answer may affect the design of algorithms which work with object graphs, such as serialization/deserialization formatters.

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


EDIT

编辑

As Brian suggested, it is indeed possible to modify the boxed value without unboxing it, by casting it to an interface type instead of the value type. So given this code:

正如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; }
}

then the reference-cycle I describe can be constructed like this:

那么我所描述的参照循环可以这样构造:

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

Which basically leaves us with reason #72 why mutable value-types are evil.

这基本上让我们明白了为什么可变价值类型是邪恶的。

3 个解决方案

#1


2  

This is possible by using an interface and having the value type implement the interface and to refer to each other. This allows them to create a cycle through boxed values since the struct when used with the interfaced reference will be boxed.

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

Quick Sample

快速样品

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

I share Brian's question though about wondering what advantage this will give you.

我同意布莱恩的问题,我想知道这对你有什么好处。

#2


1  

Honestly, I have not tried it, but see if have the Value property be on an interface, and then using the interface as your box lets you mutate the boxed itself rather than a new copy.

老实说,我还没有尝试过它,但是看看是否让Value属性位于一个接口上,然后使用接口作为您的框,让您可以修改框本身,而不是一个新的副本。

I vaguely feel like it is possible, though I'm unsure why I think that. Helpful, huh?

我隐约觉得这是可能的,尽管我不知道为什么会这样想。有帮助,嗯?

#3


0  

I didn't know structures could implement interfaces. That seems really bizarre; what's it good for? Is the dislike for structures in general, or for structures with properties and methods which act upon them? It's too bad .net doesn't allow one to declare certain structure properties and methods as mutators, whose use on "ReadOnly" structures would be forbidden.

我不知道结构可以实现接口。这似乎很奇怪;什么好处?是不喜欢一般的结构,还是不喜欢具有属性和方法的结构?很遗憾。net不允许将某些结构属性和方法声明为mutators,它禁止在“只读”结构上使用这些属性和方法。

#1


2  

This is possible by using an interface and having the value type implement the interface and to refer to each other. This allows them to create a cycle through boxed values since the struct when used with the interfaced reference will be boxed.

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

Quick Sample

快速样品

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

I share Brian's question though about wondering what advantage this will give you.

我同意布莱恩的问题,我想知道这对你有什么好处。

#2


1  

Honestly, I have not tried it, but see if have the Value property be on an interface, and then using the interface as your box lets you mutate the boxed itself rather than a new copy.

老实说,我还没有尝试过它,但是看看是否让Value属性位于一个接口上,然后使用接口作为您的框,让您可以修改框本身,而不是一个新的副本。

I vaguely feel like it is possible, though I'm unsure why I think that. Helpful, huh?

我隐约觉得这是可能的,尽管我不知道为什么会这样想。有帮助,嗯?

#3


0  

I didn't know structures could implement interfaces. That seems really bizarre; what's it good for? Is the dislike for structures in general, or for structures with properties and methods which act upon them? It's too bad .net doesn't allow one to declare certain structure properties and methods as mutators, whose use on "ReadOnly" structures would be forbidden.

我不知道结构可以实现接口。这似乎很奇怪;什么好处?是不喜欢一般的结构,还是不喜欢具有属性和方法的结构?很遗憾。net不允许将某些结构属性和方法声明为mutators,它禁止在“只读”结构上使用这些属性和方法。