2010-09-04 9 views
5

A modo de explicación, tome este tipo de valor en C#:¿Es posible crear un ciclo de referencia utilizando solo tipos de valores?

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

I puede imaginar un gráfico de objetos, donde hay dos en caja casos de este tipo, cada uno con una referencia a la otra. Esto es lo que quiero decir con un ciclo de referencia con solo tipos de valores.

Mi pregunta es si se puede o no construir un gráfico de objetos en .NET. Conceptualmente, la construcción, si es que existe, sería algo así:

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

pero, obviamente, la última línea no es válida C#. Hacer la última línea:

((ObjRef)left).Value = right; 

no logra el resultado que el elenco unboxes left y se acaba mutando una copia. Entonces, al menos en C# recta, no parece que la construcción sea posible.

¿Alguien sabe si la construcción podría lograrse utilizando reflexión, código inseguro, dynamic, código IL, o de cualquier otra manera? O, ¿alguien puede demostrar que el CLR previene eficazmente dicho ciclo de referencia?

Tenga en cuenta que en realidad no quiero crear un gráfico de objeto tal. Por el contrario, la respuesta puede afectar el diseño de algoritmos que funcionan con gráficos de objetos, como los formateadores de serialización/deserialización.


EDITAR

Como Brian sugeridos, de hecho es posible modificar el valor en caja sin unboxing que, por colada a un tipo de interfaz en lugar del tipo de valor. Así que dado este código:

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

entonces el ciclo de referencia que describo se puede construir de esta manera:

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

Lo que básicamente nos deja con la razón # 72 qué tipos de valor mutables son malos.

Respuesta

2

Esto es posible utilizando una interfaz y teniendo el tipo de valor implemente la interfaz y para referirse entre sí. Esto les permite crear un ciclo a través de los valores encuadrados ya que la estructura cuando se usa con la referencia interconectada estará encuadrada.

muestra rápida

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

que comparten la pregunta de Brian embargo sobre preguntando qué ventaja que esto le dará.

+0

No da ninguna ventaja en absoluto; como dije en la pregunta, no quiero crear este ciclo. Además, nunca escribiría un tipo de valor mutable. Sin embargo, un formateador de serialización que trabaje en gráficos de objetos arbitrarios debe ser consciente de la posibilidad y no ingresar un ciclo infinito suponiendo que los tipos de referencia siempre forman árboles y no ciclos. También puede afectar el orden en que los objetos deben ser deserializados. –

+0

Por cierto, los tipos de valores encuadrados no son realmente tipos de valores. Dentro del CLR, se manejan como clases y se comportan como clases. Lo único que los hace especiales es que * ubicaciones de almacenamiento * cuyo tipo declarado deriva del tipo de valor contendrá los datos de un elemento en lugar de una referencia de objeto. – supercat

1

Honestamente, no lo he probado, pero vea si la propiedad Value está en una interfaz, y luego usar la interfaz como su caja le permite mutar el recuadro en sí en lugar de una nueva copia.

I vagamente siento que es posible, aunque no estoy seguro de por qué pienso eso. Útil, ¿eh?

0

No sabía que las estructuras pudieran implementar interfaces. Eso parece realmente extraño; para que sirve? ¿Le disgustan las estructuras en general o las estructuras con propiedades y métodos que actúan sobre ellas? Es una lástima que .net no permita declarar ciertas propiedades y métodos de estructura como mutadores, cuyo uso en las estructuras "ReadOnly" estaría prohibido.

+1

Re: interfaces y estructuras: es bueno por la misma razón que las interfaces son útiles en los tipos de referencia, para permitirle especificar una interfaz de programación que no se preocupa por el tipo subyacente. Un tipo de valor podría implementar razonablemente IComparable e IEquatable y permitir que las clases de colección hagan suposiciones sobre el tipo que de otro modo no podrían hacer. – siride

+0

Veo su punto sobre iComparable e iEquatable. Supongo que el problema es que no hay forma de marcar métodos que mutan un objeto de aquellos que no lo hacen. No es que eso no le permita a la gente "engañar", pero evitaría la mayoría de los "errores" accidentales. – supercat

Cuestiones relacionadas