【问题标题】:C# getter and setter shorthandC# getter 和 setter 简写
【发布时间】:2011-06-27 22:41:45
【问题描述】:

如果我对这一行的内部运作的理解是正确的:

public int MyInt { get; set; }

然后它在幕后这样做:

private int _MyInt { get; set; }
Public int MyInt {
    get{return _MyInt;}
    set{_MyInt = value;}
}

我真正需要的是:

private bool IsDirty { get; set; }

private int _MyInt { get; set; }
Public int MyInt {
    get{return _MyInt;}
    set{_MyInt = value; IsDirty = true;}
}

但我想这样写:

private bool IsDirty { get; set; }

public int MyInt { get; set{this = value; IsDirty = true;} }

这不起作用。问题是我需要执行 IsDirty 的一些对象有几十个属性,我希望有一种方法可以使用自动 getter/setter,但在修改字段时仍然设置 IsDirty。

这可能吗,还是我只需要辞职以将课程中的代码量增加三倍?

【问题讨论】:

  • 改用 IronPython。它在 CLR 上,但支持面向方面的编程,这正是您所需要的。 :)
  • 如果您使用 Visual Studio,您可以创建一个代码 sn-p 以帮助您至少节省时间。

标签: c# getter-setter shorthand


【解决方案1】:

您需要自己处理:

private bool IsDirty { get; set; }

private int _myInt; // Doesn't need to be a property
Public int MyInt {
    get{return _myInt;}
    set{_myInt = value; IsDirty = true;}
}

没有可用的语法可以在仍然使用自动属性机制的同时将自定义逻辑添加到 setter。您需要使用自己的支持字段编写此内容。

这是一个常见问题 - 例如,在实现 INotifyPropertyChanged 时。

【讨论】:

  • 这正是他试图避免做的事情:)
  • @Nathan:是的——但这确实是他必须要做的——自动道具不适用于自定义逻辑。话虽如此,我的实现与 OP 不同 - 我使用字段而不是自动道具作为支持字段。
  • Bleh,那好吧。感谢现场说明。
  • 没问题,我刚刚意识到我可能还应该在其中添加一个 if(_MyInt != value) 检查,所以我只需要以详细的方式进行:)
  • 如果没有两个字段就不能这样做吗?如果可以,你能更新一下吗?
【解决方案2】:

创建一个 IsDirty 装饰器(设计模式)来包装一些需要 isDirty 标志功能的属性。

public class IsDirtyDecorator<T>
{
    public bool IsDirty { get; private set; }

    private T _myValue;
    public T Value
    {
        get { return _myValue; }
        set { _myValue = value; IsDirty = true; }
    }
}

public class MyClass
{
    private IsDirtyDecorator<int> MyInt = new IsDirtyDecorator<int>();
    private IsDirtyDecorator<string> MyString = new IsDirtyDecorator<string>();

    public MyClass()
    {
        MyInt.Value = 123;
        MyString.Value = "Hello";
        Console.WriteLine(MyInt.Value);
        Console.WriteLine(MyInt.IsDirty);
        Console.WriteLine(MyString.Value);
        Console.WriteLine(MyString.IsDirty);
    }
}

【讨论】:

  • 有趣。不过问题是,我的对象有很多属性,我真的只想要一个 IsDirty。当我的任何属性更新时,我希望更新任何一个以设置 IsDirty = true。这仍然适用于您的代码吗?
  • 这一次只适用于一个属性。每个属性都有自己的 IsDirty 标志。如果您希望所有属性都使用一个 IsDirty 标志,如果您希望它适用于每个属性,则必须修改装饰器以保存对 IsDirty 标志的引用。
【解决方案3】:

你可以让它变得简单或复杂。这取决于你想投入多少工作。您可以使用面向方面的编程通过 IL 编织器将方面添加到 IL 代码中,例如PostSharp。 或者您可以创建一个简单的类来处理您的财产的状态。前一种方法非常简单,只有在您有很多属性要以这种方式处理时才会奏效。

using System;

class Dirty<T>
{
    T _Value;
    bool _IsDirty;

    public T Value
    {
        get { return _Value; }
        set
        {
            _IsDirty = true;
            _Value = value;
        }
    }

    public bool IsDirty
    {
        get { return _IsDirty; }
    }

    public Dirty(T initValue)
    {
        _Value = initValue;
    }
}

class Program
{
    static Dirty<int> _Integer;
    static int Integer
    {
        get { return _Integer.Value; }
        set { _Integer.Value = value;  }
    }

    static void Main(string[] args)
    {
        _Integer = new Dirty<int>(10);
        Console.WriteLine("Dirty: {0}, value: {1}", _Integer.IsDirty, Integer);
        Integer = 15;
        Console.WriteLine("Dirty: {0}, value: {1}", _Integer.IsDirty, Integer);
    }
}

另一种可能性是使用在运行时生成的代理类,它会为您添加方面。对于 .NET 4,有一个类已经为您处理了这方面的问题。它被称为ExpandObject,它会在属性更改时通过事件通知您。好处是 ExpandoObject 允许您在运行时定义任意数量的属性,并且您会收到有关属性每次更改的通知。使用这种类型与 WPF 进行数据绑定非常容易。

dynamic _DynInteger = new ExpandoObject();

_DynInteger.Integer = 10;
((INotifyPropertyChanged)_DynInteger).PropertyChanged += (o, e) =>
{
    Console.WriteLine("Property {0} changed", e.PropertyName);
};

Console.WriteLine("value: {0}", _DynInteger.Integer );
_DynInteger.Integer = 20;
 Console.WriteLine("value: {0}", _DynInteger.Integer);

你的, 阿洛伊斯克劳斯

【讨论】:

    【解决方案4】:

    我将补充 Simon Hughes 的回答。我提出了同样的建议,但添加了一种允许装饰器类自动更新全局 IsDirty 标志的方法。您可能会发现以老式方式执行此操作不太复杂,但这取决于您公开了多少属性以及有多少类需要相同的功能。

    public class IsDirtyDecorator<T>
    {
        private T _myValue;
        private Action<bool> _changedAction;
    
        public IsDirtyDecorator<T>(Action<bool> changedAction = null)
        {
            _changedAction = changedAction;
        }
    
        public bool IsDirty { get; private set; }
    
        public T Value
        {
            get { return _myValue; }
            set
            {
                _myValue = value;
                IsDirty = true;
                if(_changedAction != null)
                    _changedAction(IsDirty);
            }
        }
    }
    

    现在您可以让您的装饰器类自动更新另一个类中的一些其他 IsDirty 属性:

    class MyObject
    {
        private IsDirtyDecorator<int> _myInt = new IsDirtyDecorator<int>(onValueChanged);
        private IsDirtyDecorator<int> _myOtherInt = new IsDirtyDecorator<int>(onValueChanged);
    
        public bool IsDirty { get; private set; }
    
        public int MyInt
        {
            get { return _myInt.Value; }
            set { _myInt.Value = value; }
        }
    
        public int MyOtherInt
        {
            get { return _myOtherInt.Value; }
            set { _myOtherInt.Value = value; }
        }
    
        private void onValueChanged(bool dirty)
        {
            IsDirty = true;
        }
    
    }
    

    【讨论】:

      【解决方案5】:

      我创建了一个自定义的Property&lt;T&gt; 类来执行类似的常见操作。虽然我还没有完全使用它,但它可以在这种情况下使用。

      代码可以在这里找到:http://pastebin.com/RWTWNNCU

      你可以这样使用它:

      readonly Property<int> _myInt = new Property<int>();
      public int MyInt
      {
          get { return _myInt.GetValue(); }
          set { _myInt.SetValue( value, SetterCallbackOption.OnNewValue, SetDirty ); }
      }
      
      private void SetDirty( int oldValue, int newValue )
      {
          IsDirty = true;
      }
      

      Property 类仅在通过SetterCallbackOption 参数传递新值时处理调用传递的委托。这是默认设置,因此可以删除。

      更新:

      当您需要支持多种类型(int 除外)时,这显然不起作用,因为此时委托将不匹配。您当然可以随时调整代码以满足您的需求。

      【讨论】:

        猜你喜欢
        • 2013-08-09
        • 2019-01-07
        • 2011-11-09
        • 1970-01-01
        • 1970-01-01
        • 2016-11-30
        • 1970-01-01
        • 1970-01-01
        • 2015-02-03
        相关资源
        最近更新 更多