Properties as objects

Published 14 June 04 02:42 PM

I was thinking about two items from Object Thinking:

  1. Everything is an object.
  2. Every object should provide events for when its attributes change. 

There's the idea that objects can collaborate without top-down control, if they provide & register events with each other.

My first reaction to #2 is that it violates YAGNI.  But in the interest of extremism, I'll let it ride for now.

The standard way to do #2 is something like:

 

      class Customer

      {

            int _age;

 

            public int Age

            {

                  get {

                        return this._age;

                  }

                  private set

                  {

                        this._age = value;

                        this.Age_OnChange(this, null);

                  }

            }

 

            public event System.EventHandler Age_OnChange;

      }

 

Now, you already know how much I love properties.  I’m annoyed when I read this code, because I use 15 lines of text to express what should be a very basic idea. 

 

There’s also a bunch of smelly duplication.  Not only does the word “age” appear 6 times, but 2 of them are carefully concealed in a bigger name (“Age_OnChange”), which is quite easy to miss in later code changes.  Yuck.

 

So, what if we apply #1?  What if we make an object that represents a property?  It would look like:

 

      class Property<T>

      {

            public Property(T t) { ... }

            public event System.EventHandler OnChanged;

            public T Value { ... }

      }

Well, I tried to implement it, and ran into some problems.  The biggest is that I can’t state who has permissions to set the property.  With the seed code above, only the containing class has write access to the value.

 

Here’s the best I came up with:

 

      class Property<T>

      {

            private T _value;

 

            public event System.EventHandler OnChanged;

            public T Value

            {

                  get { return this._value; }

                  set

                  {

                        this._value = value;

                        this.OnChanged(this, null);

                  }

            }

      }

 

      class Customer

      {

            public Property<int> age = new Property<int>();

 

            static void Main(string[] args)

            {

                  Customer customer = new Customer();

                  customer.age.OnChanged += delegate { Console.WriteLine("age changed"); };

 

                  customer.age.Value = 9;

            }

      }

 

I don’t think I can do any better.  Got any ideas?

 

 

Comments

# Adrian Florea said on June 14, 2004 3:41 PM:
It's exactly the idea of the PropertyHolder class that supports the Observer design pattern (see "Design Patterns in C#" book by Steven John Metsker, pp. 103-107 but also some pages before - http://www.oozinoz.com/dpcs.htm). There, Steve uses C# 1.0 (no generics) with a little help of reflection.

If you download the source code, take a look at this folder: oozinoz\app\ShowBallistics4
# Orion Adrian said on June 14, 2004 5:18 PM:
To me the problem is that there's a difference between fields and properties to the system.

My preference would be to have the ability to constrain the values of variables, not just the types. If something would try to set the variable to an unacceptable value then an exception would be thrown. However it seems rather annoying to have to write this out in a general format and not a format specifically designed for it.

Eiffel has something like this and I'd like to see C# have something like this too.

Orion Adrian
# jaybaz [MS] WebLog said on June 14, 2004 8:50 PM:
# Mike Scott said on June 15, 2004 3:32 AM:
jaybaz: don't forget to check if the value has actually changed before assigning to the private member and calling OnChanged in the set part:

set
{
if (_value != value)
{
_value = value;
OnChanged(this, null);
}
}
# Mike Scott said on June 15, 2004 3:33 AM:
Out of curiosity: why do you prefix private members with "this"?
# Ron said on June 15, 2004 6:09 AM:
'this' is used to properly distinguish exactly which variable you're using. If you have

class Person
{
public string name;

public Person(string name)
{
this.name = name;
}

the code requires 'this.' to properly clarify to the compiler just which 'name' is set. If a prefix such as '_' is used on fields, 'this.' is unnecessary, but often used anyway for the sake of clarity.
# Ron said on June 15, 2004 6:39 AM:
Jay,

Along with Mike's suggestion, I'd recommend two changes. First, create a custom EventHandler delegate and EventArgs for the OnChanged event. I prefer to return the value with the event. My inclination is to make it a nested class, but I'm sure it'll break one rule or another (and it's not a big deal to me either way).

Second, create a separate method to call OnChanged. It needs a bit of validation to ensure the call isn't made if no other component is set to receive the event.

Hopefully this doesn't violate any other principles.
# jaybaz [MS] said on June 15, 2004 8:20 AM:
Mike: It's a design question that I never answered. I suppose with a name like "OnChanged" you're right; that the behavior I wrote should be called "OnSet".
# jaybaz [MS] said on June 15, 2004 8:28 AM:
Ron: I especially like your suggestion to ExtractMethod.

I'm dumping the updated code into this comment:

class Property<T>
{
private T _value;

public delegate void SetEventHandler(object sender, T newValue);

public event SetEventHandler OnSet;
public T Value
{
get { return this._value; }
set
{
this._value = value;
FireOnSet();
}
}
void FireOnSet()
{
SetEventHandler temp = this.OnSet;
if (temp != null)
{
temp(this, this._value);
}
}
}
# Omer van Kloeten said on June 15, 2004 9:41 AM:
Jay,

1. I would have included the old value in the event for reference's sake.
2. The only problem with this is that there's no such thing as a default property, like in VB. I have to write customer.age.Value instead of doing customer.age. What happened if T was Nullable<int>? This would cause the code to be customer.age.Value.Value, which is rather ugly (yes, I know you don't have to explicitly call Value on a nullable type). customer.age.OnChanged is cool, though. :)
# jaybaz [MS] said on June 15, 2004 9:44 AM:
In these explorations I keep seeing .Value pop up. I'm afraid it's unavoidable, and my code will soon be littered with .Value.Value.Value.Value in the name of readability!
# CraigRoffers said on June 15, 2004 10:36 AM:
It would be nice if C# supported the VB concept of a default property. An attribute could be used to indicate which property use.
This would get the syntax back to what you would expect: customer.age = 9;

class Property<T>
{
private T _value;

[DefaultProperty()]
public T Value
{
get { return this._value; }
}
}
# jaybaz [MS] WebLog said on June 16, 2004 8:05 PM:
# Coad's Code Block said on June 18, 2004 2:14 AM:
# Coad's Code Block said on June 18, 2004 2:17 AM:
# public MattBerther : ISerializable said on June 23, 2004 2:42 PM:
One of my favorite bloggers as of late is Jay Bazuzi (rss), who works on the Visual C# IDE team at Microsoft. Give him a read; he's got some posts that are sure to melt your brain, such as "no...
# jaybaz MS WebLog Properties as objects | Menopause Relief said on June 9, 2009 9:18 PM:

PingBack from http://menopausereliefsite.info/story.php?id=207

# jaybaz MS WebLog Properties as objects | Cellulite Creams said on June 13, 2009 5:48 AM:

PingBack from http://cellulitecreamsite.info/story.php?id=621

New Comments to this post are disabled

This Blog

Syndication

Page view tracker