Store a reference to a value type?

前端 未结 5 1184
情书的邮戳
情书的邮戳 2020-11-29 04:51

I am writing a \"Monitor\" object to facilitate debugging of my app. This Monitor object can be accessed at run time from an IronPython interpreter. My question is, is it po

相关标签:
5条回答
  • 2020-11-29 05:26

    You cannot store a reference to a variable in a field or array. The CLR requires that a reference to a variable be in (1) a formal parameter, (2) a local, or (3) the return type of a method. C# supports (1) but not the other two.

    (ASIDE: It is possible for C# to support the other two; in fact I have written a prototype compiler that does implement those features. It's pretty neat. (See http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/ for details.) Of course one has to write an algorithm that verifies that no ref local could possibly be referring to a local that was on a now-destroyed stack frame, which gets a bit tricky, but its doable. Perhaps we will support this in a hypothetical future version of the language. (UPDATE: It was added to C# 7!))

    However, you can make a variable have arbitrarily long lifetime, by putting it in a field or array. If what you need is a "reference" in the sense of "I need to store an alias to an arbitrary variable", then, no. But if what you need is a reference in the sense of "I need a magic token that lets me read and write a particular variable", then just use a delegate, or a pair of delegates.

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

    The outer local variable x will stay alive at least until rx is reclaimed.

    0 讨论(0)
  • 2020-11-29 05:30

    Here is a pattern I came up with that I find myself using quite a bit. Usually in the case of passing properties as parameters for use on any object of the parent type, but it works just as well for a single instance. (doesn't work for local scope value types tho)

    public interface IValuePointer<T>
    {
        T Value { get; set; }
    }
    public class ValuePointer<TParent, TType> : IValuePointer<TType>
    {
        private readonly TParent _instance;
        private readonly Func<TParent, TType> _propertyExpression;
        private readonly PropertyInfo _propInfo;
        private readonly FieldInfo _fieldInfo;
    
        public ValuePointer(TParent instance, 
                            Expression<Func<TParent, TType>> 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);
            }
        }
    }
    

    This can then be used like so

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

    Notice the interface with a more limited set of template arguments, this allows you to pass the pointer to something that has no knowledge of the parent type.

    You could even implement another interface with no template arguments that calls .ToString on any value type (don't forget the null check first)

    0 讨论(0)
  • 2020-11-29 05:35

    You can literally take a pointer to a value type using usafe code

    public class Foo
    {
        public int a;
    }
    
    unsafe static class Program
    {
        static void Main(string[] args)
        {
            var f=new Foo() { a=1 };
            // f.a = 1
    
            fixed(int* ptr=&f.a)
            {
                *ptr=2;
            }
            // f.a = 2
        }
    }
    
    0 讨论(0)
  • 2020-11-29 05:37

    No - you can't store a "pointer" to a value type directly in C#.

    Typically, you'd hold a reference to the Test instance containing "a" - this gives you access to a (via testInstance.a).

    0 讨论(0)
  • 2020-11-29 05:46
    class Test
    {
        private int a;
    
        /// <summary>
        ///  points to my variable type interger,
        ///  where the identifier is named 'a'.
        /// </summary>
        public int A
        {
            get { return a; }
            set { a = value; }
        }
    }
    

    Why put yourself through all that hassle of writing complicated code, declaring identifiers everywhere linking to the same location? Make a property, add some XML code to help you outside the class, and use the properties in your coding.

    I don't know about storing a pointer, don't think it's possible, but if you're just wanting to check its value, the safest way to my knowledge is to create a property of the variable. At least that way you can check its property at any time and if the variable is static, you wouldn't even have to create an instance of the class to access the variable.

    Properties have a lot of advantages; type safety is one, XML tags another. Start using them!

    0 讨论(0)
提交回复
热议问题