C# Object Setter Not Called When Member is Modified

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-20 05:58:12

问题


I have the following wrapper class:

public class Wrapper
{
    public int Member;
}

In a separate class, I have the following:

public class ContainerClass
{
    private Wrapper data;
    public Wrapper Property
    {
        get { return data; }
        set { data = value; }
    }

    public void Foo()
    {
        Property.Member = 42;
    }
}

When Property.Member is modified in Foo(), nothing happens (the setter is skipped). However, I can still do the following, for example:

    public void Foo()
    {
        Property = Property;
    }

and enter the desired setter. So my question is, why doesn't modifying the member of an object property call that property's setter?


回答1:


Because you aren't setting the value of Property. Your code just invokes the getter of Property, then setting the value of the Member field (which would invoke the setter of Member if it were a property, which isn't the case here).

If you want to execute code when Member is set, you need to have

public class Wrapper
{
    private int member;
    public int Member
    {
        get { return this.member; }
        set 
        {
            this.member = value;
            DoSomething();
        }
    }
}

Or perhaps a more elegant solution would be to use events. The built-in INotifyProperyChanged interface gives you a pretty good template for this sort of thing.

using System.ComponentModel;

public class Wrapper : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private int member;
    public int Member
    {
        get { return this.member; }
        set 
        {
            this.member = value;
            this.OnPropertyChanged("Member");
        }
    }

    protected void OnPropertyChanged(string name)
    {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null)
      {
          handler(this, new PropertyChangedEventArgs(name));
      }
    }
}

public class ContainerClass
{
    private Wrapper data;
    public Wrapper Property
    {
        get { return data; }
        set { data = value; }
    }

    public void Foo()
    {
        data.PropertyChanged += data_PropertyChanged;
        Property.Member = 42;
    }

    private void data_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Member")
        {
            DoStuff();
        }
    }
}



回答2:


Because you aren't modifying the reference. You are modifying the reference' member.

Say, for example, if I were to stand you in the corner of the room and say, "Hold this apple". If I come in and switch the apple with a banana.. I haven't switched you, so you're happy. But if I switch you out with someone else you'll complain that I'm replacing you.

..that is my analogy for this anyway.

Also, you've prefixed a class with I.. this is generally used on interfaces in .NET land..

EDIT: I realise that if I were to stand you in a corner holding a piece of fruit.. you probably wouldn't complain when I replaced you..




回答3:


In the constructor of foo, you are setting the field of class Wrapper.

public void Foo()
{
    Property.Member = 42; // No property set, you are accessing a field.
}

In the second example, you are setting a property

public void Foo()
{
    // Setting Property "Property" to the value of "Property"
    // You should see both the getter and the setter called.
    Property = Property; 
}

I do not know what you are attempting to do, but maybe you wanted Wrapper to have a property too.

public class Wrapper
{
private int member;
public int Member
{
    get { return data; }
    set { data = value; }
}
}

Then the setter would be called on Wrapper.Member when you did Property.Member = 42




回答4:


Usually people add an object to a list directly by Add() method which, in turn, does not trigger the setter.

private List<string> _namesList = new List<string>();
// list of names
public List<string> NamesList
{    
    get
    {
    return _namesList;
    }
    set
    {
    if (value == _namesList)
    {
    return;
    }
    _namesList = value;
    }
}

In above NamesList property, if you call NamesList.Add("test") it won't invoke setter. Simple solution is store the list in a new variable and gradually set that variable to NamesList e.g.

List<string> lst = new List<string>{ "test1" };
d.NamesList = lst;              // setter will fire.

But it's a common mistake to add an object to a list/collection directly. :)



来源:https://stackoverflow.com/questions/14947309/c-sharp-object-setter-not-called-when-member-is-modified

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!