Joseph
Joseph

Reputation: 953

C# Object Setter Not Called When Member is Modified

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?

Upvotes: 0

Views: 8048

Answers (4)

Ritesh Jain
Ritesh Jain

Reputation: 1

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. :)

Upvotes: 0

p.s.w.g
p.s.w.g

Reputation: 148980

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

Upvotes: 2

Simon Whitehead
Simon Whitehead

Reputation: 65049

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..

Upvotes: 3

Phillip Scott Givens
Phillip Scott Givens

Reputation: 5464

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

Upvotes: 0

Related Questions