简体   繁体   English

C#getter和setter简写

[英]C# getter and setter shorthand

If my understanding of the internal workings of this line is correct: 如果我对这条线的内部运作的理解是正确的:

public int MyInt { get; set; }

Then it behind the scenes does this: 然后在幕后做这个:

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

What I really need is: 我真正需要的是:

private bool IsDirty { get; set; }

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

But I would like to write it something like: 但我想写一些类似于:

private bool IsDirty { get; set; }

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

Which does not work. 哪个不起作用。 The thing is some of the objects I need to do the IsDirty on have dozens of properties and I'm hoping there is a way to use the auto getter/setter but still set IsDirty when the field is modified. 事情是我需要做的一些对象,IsDirty上有几十个属性,我希望有一种方法可以使用auto getter / setter,但是当字段被修改时仍然设置IsDirty。

Is this possible or do I just have to resign myself to tripling the amount of code in my classes? 这是可能的还是我只需要让自己在我的班级中将代码量增加三倍?

You'll need to handle this yourself: 你需要自己处理:

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

There is no syntax available which adds custom logic to a setter while still using the automatic property mechanism. 没有可用的语法,在仍然使用自动属性机制的同时将自定义逻辑添加到setter。 You'll need to write this with your own backing field. 您需要使用自己的支持字段来编写此代码。

This is a common issue - for example, when implementing INotifyPropertyChanged . 这是一个常见问题 - 例如,在实现INotifyPropertyChanged

Create an IsDirty decorator (design pattern) to wrap some your properties requiring the isDirty flag functionality. 创建一个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);
    }
}

You can make it simple or complex. 你可以简单或复杂。 It depends on how much work you want to invest. 这取决于你想投入多少工作。 You can use aspect oriented programming to add the aspect via an IL weaver into the IL code with eg PostSharp . 您可以使用面向方面编程通过IL weaver将方面添加到IL代码中,例如使用PostSharp Or you can create a simple class that does handle the state for your property. 或者,您可以创建一个处理属性状态的简单类。 It is so simple that the former approach only pays off if you have really many properties to handle this way. 这很简单,如果你有很多属性来处理这种方式,前一种方法只会得到回报。

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

Another possibility is to use a proxy class which is generated at runtime which does add the aspect for you. 另一种可能性是使用在运行时生成的代理类,它会为您添加方面。 With .NET 4 there is a class that does handle this aspect already for you. 使用.NET 4,有一个类已经为您处理这方面。 It is called ExpandObject which does notify you via an event when a property changes. 它被称为ExpandObject ,它会在属性发生变化时通过事件通知您。 The nice things is that ExpandoObject allows you to define at runtime any amount of properties and you get notifications about every change of a property. 好处是ExpandoObject允许您在运行时定义任何数量的属性,并获得有关属性的每个更改的通知。 Databinding with WPF is very easy with this type. 使用此类型,使用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);

Yours, Alois Kraus 你的,Alois Kraus

I'm going to add on to Simon Hughes' answer. 我要补充Simon Hughes的回答。 I propose the same thing, but add a way to allow the decorator class to update a global IsDirty flag automatically. 我提出了相同的建议,但添加了一种方法来允许装饰器类自动更新全局IsDirty标志。 You may find it to be less complex to do it the old-fashioned way, but it depends on how many properties you're exposing and how many classes will require the same functionality. 您可能会发现以旧式方式执行此操作并不复杂,但这取决于您要公开的属性数量以及需要相同功能的类别数量。

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

Now you can have your decorator class automatically update some other IsDirty property in another class: 现在,您可以让您的装饰器类自动更新另一个类中的其他一些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;
    }

}

I have created a custom Property<T> class to do common operations like that. 我已经创建了一个自定义Property<T>类来执行这样的常见操作。 I haven't used it thoroughly yet though, but it could be used in this scenario. 虽然我还没有彻底使用它,但它可以在这种情况下使用。

Code can be found here: http://pastebin.com/RWTWNNCU 代码可以在这里找到: http//pastebin.com/RWTWNNCU

You could use it as follows: 您可以按如下方式使用它:

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

The Property class handles only calling the passed delegate when a new value is passed thanks to the SetterCallbackOption parameter. 由于SetterCallbackOption参数传递新值,Property类仅处理调用传递的委托。 This is default so it can be dropped. 这是默认设置,因此可以删除它。

UPDATE: 更新:

This won't work apparently when you need to support multiple types (besides int ), because the delegate won't match then. 当你需要支持多种类型(除了int )之外,这显然不会起作用,因为委托将不匹配。 You could ofcourse always adjust the code to suit your needs. 您可以随时调整代码以满足您的需求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM