Almacenar una referencia a un tipo de valor?

Estoy escribiendo un objeto “Monitor” para facilitar la depuración de mi aplicación. Se puede acceder a este objeto Monitor en tiempo de ejecución desde un intérprete IronPython. Mi pregunta es, ¿es posible en C # almacenar una referencia a un tipo de valor? Digamos que tengo la siguiente clase:

class Test { public int a; } 

¿Puedo de alguna manera almacenar un “puntero” a “a” para poder verificar su valor en cualquier momento? ¿Es posible usar un código seguro y administrado?

Gracias.

No puede almacenar una referencia a una variable en un campo o matriz. El CLR requiere que una referencia a una variable esté en (1) un parámetro formal, (2) un local, o (3) el tipo de retorno de un método. C # admite (1) pero no los otros dos.

(ASIDE: Es posible que C # sea compatible con los otros dos, de hecho, he escrito un prototipo de comstackdor que sí implementa esas características. Es bastante prolijo. (Ver http://ericlippert.com/2011/06/23/ref- returns-and-ref-locals / para más detalles). Por supuesto, uno tiene que escribir un algoritmo que verifique que ningún ref local podría estar refiriéndose a un local que estaba en un marco de stack ahora destruido, lo cual es un poco complicado, pero es factible. Quizás apoyaremos esto en una versión futura hipotética del lenguaje. (ACTUALIZACIÓN: ¡Se agregó a C # 7!))

Sin embargo, puede hacer que una variable tenga una duración arbitrariamente larga, poniéndola en un campo o matriz. Si lo que necesita es una “referencia” en el sentido de “Necesito almacenar un alias para una variable arbitraria”, entonces, no. Pero si lo que necesita es una referencia en el sentido de “Necesito un token mágico que me permita leer y escribir una variable en particular”, simplemente use un delegado o un par de delegates.

 sealed class Ref { private Func getter; private Action setter; public Ref(Func getter, Action setter) { this.getter = getter; this.setter = setter; } public T Value { get { return getter(); } set { setter(value); } } } ... Ref M() { string x = "hello"; Ref rx = new Ref(()=>x, v=>{x=v;}); rx.Value = "goodbye"; Console.WriteLine(x); // goodbye return rx; } 

La variable local externa x permanecerá activa al menos hasta que se reclame rx.

No, no puede almacenar un “puntero” a un tipo de valor directamente en C #.

Por lo general, mantendrá una referencia a la instancia de prueba que contiene “a”; esto le da acceso a a (a través de testInstance.a ).

Aquí hay un patrón que se me ocurrió que me encuentro usando bastante. Por lo general, en el caso de pasar propiedades como parámetros para usar en cualquier objeto del tipo padre, pero funciona igual de bien para una sola instancia. (no funciona para tipos de valor de scope local)

 public interface IValuePointer { T Value { get; set; } } public class ValuePointer : IValuePointer { private readonly TParent _instance; private readonly Func _propertyExpression; private readonly PropertyInfo _propInfo; private readonly FieldInfo _fieldInfo; public ValuePointer(TParent instance, Expression> propertyExpression) { _instance = instance; _propertyExpression = propertyExpression.Compile(); _propInfo = ((MemberExpression)(propertyExpression).Body).Member as PropertyInfo; _fieldInfo = ((MemberExpression)(propertyExpression).Body).Member as FieldInfo; } public TType Value { get { return _propertyExpression.Invoke(_instance); } set { if (_fieldInfo != null) { _fieldInfo.SetValue(_instance, value); return; } _propInfo.SetValue(_instance, value, null); } } } 

Esto puede usarse como tal

 class Test { public int a; } void Main() { Test testInstance = new Test(); var pointer = new ValuePointer(testInstance,x=> xa); testInstance.a = 5; int copyOfValue = pointer.Value; pointer.Value = 6; } 

Observe la interfaz con un conjunto más limitado de argumentos de plantilla, esto le permite pasar el puntero a algo que no tiene conocimiento del tipo principal.

Incluso podría implementar otra interfaz sin argumentos de plantilla que llame a .ToString en cualquier tipo de valor (no olvide primero la comprobación nula)

Literalmente puede tomar un puntero a un tipo de valor usando el código usafe

 public class Foo { public int a; } unsafe static class Program { static void Main(string[] args) { var f=new Foo() { a=1 }; // fa = 1 fixed(int* ptr=&f.a) { *ptr=2; } // fa = 2 } } 
 class Test { private int a; ///  /// points to my variable type interger, /// where the identifier is named 'a'. ///  public int A { get { return a; } set { a = value; } } } 

¿Por qué pasar por todas esas complicaciones de escribir código complicado, declarando identificadores en todas partes que enlazan a la misma ubicación? Cree una propiedad, agregue código XML para ayudarlo fuera de la clase y use las propiedades en su encoding.

No sé cómo almacenar un puntero, no creo que sea posible, pero si solo quieres comprobar su valor, la forma más segura que yo sepa es crear una propiedad de la variable. Al menos de esa manera puede verificar su propiedad en cualquier momento y si la variable es estática, ni siquiera tendrá que crear una instancia de la clase para acceder a la variable.

Las propiedades tienen muchas ventajas; tipo de seguridad es uno, XML etiqueta otro. Comience a usarlos!