Property backing value scope

前端 未结 6 1316
情书的邮戳
情书的邮戳 2021-02-12 19:10

Is anything like this possible? I\'m assuming not, but it looks good to me:

class MyClass {
    public int Foo {
        get { return m_foo; }
        s         


        
相关标签:
6条回答
  • 2021-02-12 19:32

    If you would like to avoid generics, you could always hide the _backingField and the bounds checking in a private inner class. You could even hide it further by making the outer class partial. Of course, there would have to be some delegating going on between the outer and the inner class, which is a bummer. Code to explain my thoughts:

    public partial class MyClass
    {
        public int Property
        {
            get { return _properties.Property; }
            set { _properties.Property = value; }
        }
    
        public void Stuff()
        {
            // Can't get to _backingField...
        }
    }
    
    public partial class MyClass
    {
        private readonly Properties _properties = new Properties();
    
        private class Properties
        {
            private int _backingField;
    
            public int Property
            {
                get { return _backingField; }
                set
                {
                    // perform checks
                    _backingField = value;
                }
            }
        }
    }
    

    But this is a lot of code. To justify all that boiler plate, the original problem has to be quite severe...

    0 讨论(0)
  • 2021-02-12 19:36

    Here's my take on that:

    public class WrappedField<T>
    {
        public class Internals
        {
            public T Value;
        }
    
        private readonly Internals _internals = new Internals();
        private readonly Func<Internals, T> _get;
        private readonly Action<Internals, T> _set;
    
        public T Value
        {
            get { return _get(_internals); }
            set { _set(_internals, value); }
        }
    
        public WrappedField(Func<Internals, T> get, Action<Internals, T> set)
        {
            _get = get;
            _set = set;            
        }
    
        public WrappedField(Func<Internals, T> get, Action<Internals, T> set, T initialValue)
            : this(get, set)
        {
            _set(_internals, initialValue);
        }
    }
    

    Usage:

    class Program
    {
        readonly WrappedField<int> _weight = new WrappedField<int>(
            i => i.Value,           // get
            (i, v) => i.Value = v,  // set
            11);                    // initialValue
    
        static void Main(string[] args)
        {
            Program p = new Program();
            p._weight.Value = 10;
    
            Console.WriteLine(p._weight.Value);
        }
    }
    
    0 讨论(0)
  • 2021-02-12 19:39

    The short answer is no, that's not possible in C# today.

    We get a feature request like this fairly often; it's a nice feature in its more general form. The more general form is to more clearly make the lifetime of a local variable orthogonal to its scope.

    Just to make sure those terms are clear: a variable is a storage location, possibly named. Every variable has a lifetime: the amount of time at runtime in which the variable is guaranteed to refer to valid storage. The scope of a name is the region of text in which that name may be used; it is a compile-time concept, not a runtime concept. A local variable is a variable whose scope is a statement block.

    In many languages, the lifetime of a local variable is closely tied to its scope: when control logically enters the scope at runtime, the lifetime begins and when it leaves the scope, the lifetime ends. This is true in C# with some notable caveats:

    • The lifetime of a local may be extended or truncated if the runtime can determine that doing so has no consequence to the action of managed code on the current thread. The actions of other threads (like the finalizer thread) and unmanaged code on the current thread are implementation-defined.

    • The lifetime of a local that is in an iterator block, an async method, or a closed-over outer variable of an anonymous function, may be extended to match or exceed the lifetime of the iterator, task, delegate or expression tree that uses it.

    Clearly it is not a requirement that the lifetime and scope of a local be tied together in any way. It would be nice if we could explicitly have locals that have the lifetime of an instance or static field, but the scope of a local. C has this feature; you can make a "static" local variable. C# does not. Your proposal is essentially to allow a local variable within the block of the property that has the lifetime of the instance but whose scope is restricted to the block.

    I would classify this feature as "nice". We have a list of potential "nice" features literally as long as your arm that we don't have time to implement, so I wouldn't expect this one to make it to the top of the list any time soon. Thanks for the feedback though; it helps us prioritize that list somewhat.

    0 讨论(0)
  • 2021-02-12 19:48

    Well, it's rather difficult to deal with, probably not very performant, and not something I'd really use, but technically it's a way of obscuring the backing field from the rest of the class.

    public class MySuperAwesomeProperty<T>
    {
        private T backingField;
        private Func<T, T> getter;
        private Func<T, T> setter;
        public MySuperAwesomeProperty(Func<T, T> getter, Func<T, T> setter)
        {
            this.getter = getter;
            this.setter = setter;
        }
    
        public T Value
        {
            get
            {
                return getter(backingField);
            }
            set
            {
                backingField = setter(value);
            }
        }
    }
    
    public class Foo
    {
        public MySuperAwesomeProperty<int> Bar { get; private set; }
    
    
        public Foo()
        {
            Bar = new MySuperAwesomeProperty<int>(
                value => value, value => { doStuff(); return value; });
    
            Bar.Value = 5;
    
            Console.WriteLine(Bar.Value);
        }
    
        private void doStuff()
        {
            throw new NotImplementedException();
        }
    }
    
    0 讨论(0)
  • 2021-02-12 19:50

    According to the C# 4.0 language specifications.

    However, unlike fields, properties do not denote storage locations. Instead, properties have accessors that specify the statements to be executed when their values are read or written.

    Adding a field would require a memory location. So no, this is not possible.

    0 讨论(0)
  • 2021-02-12 19:57

    Nope, the only thing that can be within the the body of the property is the get and set.

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