By way of explanation, take this value type in 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:
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:
((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.
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?
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 gra开发者_如何学JAVAphs, 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:
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.
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.
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.
I vaguely feel like it is possible, though I'm unsure why I think that. Helpful, huh?
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.
精彩评论