473,386 Members | 1,668 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Making C# properties act like member variables

I am an experienced C++ programmer with over 12 years of development, and I
think I know C++ quite well. I'm changing jobs at the moment, and I have
about a month between leaving my last job and starting my new one. In that
time, I have decided to learn C#. I picked up the book, "Programming C#
(4th Edition)" recently and have read most of it. I've written about 1,500
lines of C# now, and I've run into the first really ugly thing I don't like
about the language - properties act like member variables, but they don't do
a good enough job of it.

Here's some sample code that demonstrates the issue I found. In computer
graphics, which is one of my programming specialties, colors are represented
by red, green, blue, and alpha components. Frequently these values are
expressed as floats, but they're also just as frequently expressed as bytes,
often with all 4 bytes packed into a single uint32. Most standard 3d
graphics pipelines (Direct3D and OpenGL) have the concept of a Material,
which indicates how light is reflected off the surface (basically you end up
multiplying the incoming light color by the material color in a
component-wise manner). Materials typically contain multiple colors -
Ambient, Diffuse, Emissive, and Specular, but I have included only the
diffuse color in this example to keep the code shorter.

In this sample, I have chosen to refactor the Material class and convert the
internal representation of the color from the 4-component byte
representation to the 4-component float representation.

namespace PropertyExample
{
public class FloatRgba
{
public float r = 1.0f;
public float g = 1.0f;
public float b = 1.0f;
public float a = 1.0f;

public FloatRgba()
{
}

public FloatRgba(float r, float g, float b, float a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}

public void Invert()
{
r = 1.0f - r;
g = 1.0f - g;
b = 1.0f - b;
a = 1.0f - a;
}
}

public class ByteRgba
{
public byte r = 255;
public byte g = 255;
public byte b = 255;
public byte a = 255;

public void Invert()
{
r = (byte)(255 - r);
g = (byte)(255 - g);
b = (byte)(255 - b);
a = (byte)(255 - a);
}
}

public class MaterialBefore
{
public ByteRgba diffuseColor = new ByteRgba();
public FloatRgba DiffuseColor
{
get
{
return new FloatRgba(
(float)diffuseColor.r / 255.0f,
(float)diffuseColor.g / 255.0f,
(float)diffuseColor.b / 255.0f,
(float)diffuseColor.a / 255.0f);
}
set
{
if (value.r < 0.0f || value.r > 1.0f || value.g < 0.0f ||
value.g > 1.0f || value.b < 0.0f || value.b > 1.0f || value.a < 0.0f ||
value.a > 1.0f)
throw new System.ArgumentOutOfRangeException();

diffuseColor.r = (byte)(value.r / 255.0f);
diffuseColor.g = (byte)(value.g / 255.0f);
diffuseColor.b = (byte)(value.b / 255.0f);
diffuseColor.a = (byte)(value.a / 255.0f);
}
}
}

public class MaterialAfter
{
public FloatRgba diffuseColor = new FloatRgba();
public FloatRgba DiffuseColor
{
get { return diffuseColor; }
set { diffuseColor = value; }
}
}

class Program
{
static void Main(string[] args)
{
MaterialBefore m0 = new MaterialBefore();
MaterialAfter m1 = new MaterialAfter();

System.Console.WriteLine("m0 before: " +
m0.diffuseColor.r.ToString());
System.Console.WriteLine("m1 before: " +
m1.diffuseColor.r.ToString());

m0.DiffuseColor.Invert();
m1.DiffuseColor.Invert();

System.Console.WriteLine("m0 after: " +
m0.diffuseColor.r.ToString());
System.Console.WriteLine("m1 after: " +
m1.diffuseColor.r.ToString());
}
}
}
In refactoring Material from MaterialBefore to MaterialAfter, the hope is to
prevent any client code from breaking when the internal representation of
the diffuse color is changed from bytes to floats. In the case of
m0.DiffuseColor.Invert(), the actual m0 object will be modified since the
DiffuseColor get method returns a reference to the actual object. In the
case of m1.DiffuseColor.Invert(), the temporary will be inverted and there
will be no change to the m1 object as the programmer expected. This
refactoring has introduced a very subtle and hard to find bug. It seems to
me that this will happen any time the programmer changes the internal
representation of a class such that a member is converted to a property
returning a temporary, or the existing property can no longer return a
member variable and is forced to return a temporary in a vain effort to keep
the API compatible.

Is there a decent way within the language to deal with this? I've been
pondering some solutions myself, but I don't really like any of them so far.
If C# had the notion of const like C++, I could make get accessors return
const objects so that I wouldn't have to worry about the client code trying
to change the object. I considered making every property get return a
temporary, but then properties have the same syntax as member variables but
act very definitely. I've also considered returning some sort of proxy
object that exposes a ByteRgba interface but internally holds a reference to
the FloatRgba version of diffuseColor and can modify that object when it
changes, but I think that would require fairly extensive changes to both
ByteRbga and FloatRbga, and that change may be very difficult if we were
dealing with more complex types.

In fact, thinking about the whole issue again, I don't think that the
problem is limited to properties - it would happen with a getDiffuseColor()
routine as well. Am I missing something obvious?

Thanks,

j
Jeff Grills
Nov 17 '05 #1
10 1842
The scenario you describe might be a more complex issue than what I'm
describing, but my 2c anyway.

1. Initially you had the following (in the MaterialBefore scenario).
a. Two classes ByteRgba and FloatRgba
b. MaterialBefore internally stored ByteRgba
c. MaterialBefore exposed a property of type FloatRgba which
returned a NEW object everytime the get accessor was called.
In this scenario, the programmer who made a change to the object returned
had to call the set accessor in order to get the change in the class

2. In the refactoring scenario, the internal representation of
MaterialBefore was changed to store a FloatRgba, doing away with the
ByteRgba class. However, when you implement the get/set accessor, you return
a reference to the same object instead on a new object. This represents a
design change and the code is not going to work the same way. In this case,
the programmer (client) do not have to call set to change the internal
representation of the class.

As you noted, this is not a language issue. You'll see the same issue
whether you use C++ or C# and a method instead of the property.

My understanding is that since MaterialBefore did a new on every get access,
you'll have to preserve the same bahavior in the new class MaterialAfter,
wither by reconstructing the class explicitly or by adding a Clone() method
to the class.

Another design pattern you might consider in this case is to inherit all the
different implementations of color from a base class which has virtual
methods/properties like Invert(), Clone(), etc. The Material Class can store
a variable of type BaseClass. This way, you can change the underlying
construction without refactoring any code.

Hope this helps
--
- Shuvro
SDE, MSFT

This posting is provided "AS IS" with no warranties, and confers no rights.
Use of included script samples are subject to the terms specified at
http://www.microsoft.com/info/cpyright.htm.

"Jeff Grills" <jg***********@drivensnow.org> wrote in message
news:O1**************@TK2MSFTNGP15.phx.gbl...
I am an experienced C++ programmer with over 12 years of development, and I
think I know C++ quite well. I'm changing jobs at the moment, and I have
about a month between leaving my last job and starting my new one. In that
time, I have decided to learn C#. I picked up the book, "Programming C#
(4th Edition)" recently and have read most of it. I've written about 1,500
lines of C# now, and I've run into the first really ugly thing I don't like
about the language - properties act like member variables, but they don't
do a good enough job of it.

Here's some sample code that demonstrates the issue I found. In computer
graphics, which is one of my programming specialties, colors are
represented by red, green, blue, and alpha components. Frequently these
values are expressed as floats, but they're also just as frequently
expressed as bytes, often with all 4 bytes packed into a single uint32.
Most standard 3d graphics pipelines (Direct3D and OpenGL) have the concept
of a Material, which indicates how light is reflected off the surface
(basically you end up multiplying the incoming light color by the material
color in a component-wise manner). Materials typically contain multiple
colors - Ambient, Diffuse, Emissive, and Specular, but I have included
only the diffuse color in this example to keep the code shorter.

In this sample, I have chosen to refactor the Material class and convert
the internal representation of the color from the 4-component byte
representation to the 4-component float representation.

namespace PropertyExample
{
public class FloatRgba
{
public float r = 1.0f;
public float g = 1.0f;
public float b = 1.0f;
public float a = 1.0f;

public FloatRgba()
{
}

public FloatRgba(float r, float g, float b, float a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}

public void Invert()
{
r = 1.0f - r;
g = 1.0f - g;
b = 1.0f - b;
a = 1.0f - a;
}
}

public class ByteRgba
{
public byte r = 255;
public byte g = 255;
public byte b = 255;
public byte a = 255;

public void Invert()
{
r = (byte)(255 - r);
g = (byte)(255 - g);
b = (byte)(255 - b);
a = (byte)(255 - a);
}
}

public class MaterialBefore
{
public ByteRgba diffuseColor = new ByteRgba();
public FloatRgba DiffuseColor
{
get
{
return new FloatRgba(
(float)diffuseColor.r / 255.0f,
(float)diffuseColor.g / 255.0f,
(float)diffuseColor.b / 255.0f,
(float)diffuseColor.a / 255.0f);
}
set
{
if (value.r < 0.0f || value.r > 1.0f || value.g < 0.0f ||
value.g > 1.0f || value.b < 0.0f || value.b > 1.0f || value.a < 0.0f ||
value.a > 1.0f)
throw new System.ArgumentOutOfRangeException();

diffuseColor.r = (byte)(value.r / 255.0f);
diffuseColor.g = (byte)(value.g / 255.0f);
diffuseColor.b = (byte)(value.b / 255.0f);
diffuseColor.a = (byte)(value.a / 255.0f);
}
}
}

public class MaterialAfter
{
public FloatRgba diffuseColor = new FloatRgba();
public FloatRgba DiffuseColor
{
get { return diffuseColor; }
set { diffuseColor = value; }
}
}

class Program
{
static void Main(string[] args)
{
MaterialBefore m0 = new MaterialBefore();
MaterialAfter m1 = new MaterialAfter();

System.Console.WriteLine("m0 before: " +
m0.diffuseColor.r.ToString());
System.Console.WriteLine("m1 before: " +
m1.diffuseColor.r.ToString());

m0.DiffuseColor.Invert();
m1.DiffuseColor.Invert();

System.Console.WriteLine("m0 after: " +
m0.diffuseColor.r.ToString());
System.Console.WriteLine("m1 after: " +
m1.diffuseColor.r.ToString());
}
}
}
In refactoring Material from MaterialBefore to MaterialAfter, the hope is
to prevent any client code from breaking when the internal representation
of the diffuse color is changed from bytes to floats. In the case of
m0.DiffuseColor.Invert(), the actual m0 object will be modified since the
DiffuseColor get method returns a reference to the actual object. In the
case of m1.DiffuseColor.Invert(), the temporary will be inverted and there
will be no change to the m1 object as the programmer expected. This
refactoring has introduced a very subtle and hard to find bug. It seems
to me that this will happen any time the programmer changes the internal
representation of a class such that a member is converted to a property
returning a temporary, or the existing property can no longer return a
member variable and is forced to return a temporary in a vain effort to
keep the API compatible.

Is there a decent way within the language to deal with this? I've been
pondering some solutions myself, but I don't really like any of them so
far. If C# had the notion of const like C++, I could make get accessors
return const objects so that I wouldn't have to worry about the client
code trying to change the object. I considered making every property get
return a temporary, but then properties have the same syntax as member
variables but act very definitely. I've also considered returning some
sort of proxy object that exposes a ByteRgba interface but internally
holds a reference to the FloatRgba version of diffuseColor and can modify
that object when it changes, but I think that would require fairly
extensive changes to both ByteRbga and FloatRbga, and that change may be
very difficult if we were dealing with more complex types.

In fact, thinking about the whole issue again, I don't think that the
problem is limited to properties - it would happen with a
getDiffuseColor() routine as well. Am I missing something obvious?

Thanks,

j
Jeff Grills

Nov 17 '05 #2
I changed some of the sample code just before posting it to try to make it
more realistic, and I ended up messing it up. I'm terribly sorry. I've
re-written the sample code to make it much easier to demonstrate the
problem, although it does make it more artificial. Below is the "improved"
code.

Basically, during the refactoring process, I've replaced the FloatRgba
member with separate float variables for r, g, b, and a, but I wanted to
preserve the Diffuse property. In order to return a FloatRgba from
MaterialAfter.Diffuse.get, I have to construct a temporary object. Any
changes to it will not be reflected in the MaterialAfter object as they were
before using the MaterialBefore object. From this example, it doesn't seem
like properties in C# are appropriate for data encapsulation - the
implementation details leak through the interface in an undesirable way.

I do believe this is a language issue, but not a method vs. property issue.
If this were C++, I could at least make the return type of
MaterialAfter.Diffuse.get be a const FloatRgba, and then any attempts to
modify that variable would be caught by the compiler and the client code
could be fixed. While that doesn't meet the goal of preserving the exact
behavior of the class before and after, any client code that only reads the
value would continue to work without being changed, and any code that
modified the return value would no longer compile, which would make it easy
to find and fix.

namespace ImprovedPropertyExample
{
public class FloatRgba
{
public float r = 1.0f;
public float g = 1.0f;
public float b = 1.0f;
public float a = 1.0f;

public FloatRgba()
{
}

public FloatRgba(float r, float g, float b, float a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}

public void Invert()
{
r = 1.0f - r;
g = 1.0f - g;
b = 1.0f - b;
a = 1.0f - a;
}
}

public class MaterialBefore
{
public FloatRgba diffuseColor = new FloatRgba();
public FloatRgba DiffuseColor
{
get { return diffuseColor; }
set { diffuseColor = value; }
}
}

public class MaterialAfter
{
public float diffuseR = 1.0f;
public float diffuseG = 1.0f;
public float diffuseB = 1.0f;
public float diffuseA = 1.0f;

public FloatRgba DiffuseColor
{
get
{
return new FloatRgba(diffuseR, diffuseG, diffuseB,
diffuseA);
}
set
{
diffuseR = value.r;
diffuseG = value.g;
diffuseB = value.b;
diffuseA = value.a;
}
}
}

class Program
{
static void Main(string[] args)
{
MaterialBefore materialBefore = new MaterialBefore();
MaterialAfter materialAfter = new MaterialAfter();

System.Console.WriteLine("materialBefore initial: " +
materialBefore.diffuseColor.r.ToString());
System.Console.WriteLine("materialAfter initial: " +
materialAfter.diffuseR.ToString());

materialBefore.DiffuseColor.Invert();
materialAfter.DiffuseColor.Invert();

System.Console.WriteLine("materialBefore final: " +
materialBefore.diffuseColor.r.ToString());
System.Console.WriteLine("materialAfter final: " +
materialAfter.diffuseR.ToString());
}
}
}
Nov 17 '05 #3
> Is there a decent way within the language to deal with this? I've been
pondering some solutions myself, but I don't really like any of them so
far. If C# had the notion of const like C++, I could make get accessors
return const objects so that I wouldn't have to worry about the client
code trying to change the object. I considered making every property get
return a temporary, but then properties have the same syntax as member
variables but act very definitely. I've also considered returning some
sort of proxy object that exposes a ByteRgba interface but internally
holds a reference to the FloatRgba version of diffuseColor and can modify
that object when it changes, but I think that would require fairly
extensive changes to both ByteRbga and FloatRbga, and that change may be
very difficult if we were dealing with more complex types.

In fact, thinking about the whole issue again, I don't think that the
problem is limited to properties - it would happen with a
getDiffuseColor() routine as well. Am I missing something obvious?


Well, your mistake is to create a mutable type and have a property return a
temporary copy of it. That will almost always cause a mess, since your
property and the type are at odds(they type says "yes I'm modifiable" but
the property is written in such a way as to asusme that the type won't be
modified). I would personally modify Invert and your other methods so that
it returns a new FloatRbga and change FloatRbga so that it is immutable.
This is a pretty common pattern in the .NET world, System.String is a good
example. You might also consider adding Invert support a level up so that
your clients won't have to use the properties.

Const is a bandaid over the issue, in that it stops users from modifying an
object that was clearly designed to be modified. It reduces the concerns you
ahve, but it would be inconsistent, IMHO, to tell a client they can't modify
a given class right now, but can some place else. The problem here is really
that you are writing C++ code in C#, which just doesn't work, there is no
const, so you have to think about modifiability when designing the type not
the interfaces that use it. Given time you'll start thinking more along the
lines of the language and probably have fewer problems like this.
Nov 17 '05 #4

Daniel O'Connell [C# MVP] wrote:
Is there a decent way within the language to deal with this? I've been
pondering some solutions myself, but I don't really like any of them so
far. If C# had the notion of const like C++, I could make get accessors
return const objects so that I wouldn't have to worry about the client
code trying to change the object. I considered making every property get
return a temporary, but then properties have the same syntax as member
variables but act very definitely. I've also considered returning some
sort of proxy object that exposes a ByteRgba interface but internally
holds a reference to the FloatRgba version of diffuseColor and can modify
that object when it changes, but I think that would require fairly
extensive changes to both ByteRbga and FloatRbga, and that change may be
very difficult if we were dealing with more complex types.

In fact, thinking about the whole issue again, I don't think that the
problem is limited to properties - it would happen with a
getDiffuseColor() routine as well. Am I missing something obvious?


Well, your mistake is to create a mutable type and have a property return a
temporary copy of it. That will almost always cause a mess, since your
property and the type are at odds(they type says "yes I'm modifiable" but
the property is written in such a way as to asusme that the type won't be
modified). I would personally modify Invert and your other methods so that
it returns a new FloatRbga and change FloatRbga so that it is immutable.
This is a pretty common pattern in the .NET world, System.String is a good
example. You might also consider adding Invert support a level up so that
your clients won't have to use the properties.


My instinct would be that Color should be a value type, not a reference
type, since it 'clearly' has value semantics. Doing that fixes these
problems, but does it introduce any others?

(I note, *after* having myinstinct I should add :), that .NET's Color
type is a value type, so at least one person agrees with me...)

--
Larry Lard
Replies to group please

Nov 17 '05 #5

"Larry Lard" <la*******@hotmail.com> wrote in message
news:11*********************@g47g2000cwa.googlegro ups.com...

Daniel O'Connell [C# MVP] wrote:
> Is there a decent way within the language to deal with this? I've been
> pondering some solutions myself, but I don't really like any of them so
> far. If C# had the notion of const like C++, I could make get accessors
> return const objects so that I wouldn't have to worry about the client
> code trying to change the object. I considered making every property
> get
> return a temporary, but then properties have the same syntax as member
> variables but act very definitely. I've also considered returning some
> sort of proxy object that exposes a ByteRgba interface but internally
> holds a reference to the FloatRgba version of diffuseColor and can
> modify
> that object when it changes, but I think that would require fairly
> extensive changes to both ByteRbga and FloatRbga, and that change may
> be
> very difficult if we were dealing with more complex types.
>
> In fact, thinking about the whole issue again, I don't think that the
> problem is limited to properties - it would happen with a
> getDiffuseColor() routine as well. Am I missing something obvious?


Well, your mistake is to create a mutable type and have a property return
a
temporary copy of it. That will almost always cause a mess, since your
property and the type are at odds(they type says "yes I'm modifiable" but
the property is written in such a way as to asusme that the type won't be
modified). I would personally modify Invert and your other methods so
that
it returns a new FloatRbga and change FloatRbga so that it is immutable.
This is a pretty common pattern in the .NET world, System.String is a
good
example. You might also consider adding Invert support a level up so
that
your clients won't have to use the properties.


My instinct would be that Color should be a value type, not a reference
type, since it 'clearly' has value semantics. Doing that fixes these
problems, but does it introduce any others?

(I note, *after* having myinstinct I should add :), that .NET's Color
type is a value type, so at least one person agrees with me...)


Yes, a value type is generally the way to go, since you are correct that it
exposes value semantics, but so does string, which is a class, ;).

Without knowing precisely waht was going on, I didn't want to suggest it,
but I would definatly consider it.

Good call.
Nov 17 '05 #6
Did you happen to read my reply to the other response where I mentioned I
completely messed up the code sample? The new example I gave is much more
appropriate. In this case, I actually want to keep the reference semantics,
but the refactored doesn't have a persistent object that it can return. To
me, this means that a property that returns a reference type can't be used
for any real sort of data encapsulation, but because you do write methods
for get and set, you can potentially do other interesting things (for
instance, I have written an Object.Controller.set function that will call
Controller.SetOwner() on the controller whenever the controller is assigned
to the object).

Perhaps that's my whole issue - the book I read on C# proposed properties as
some great data encapsulation system, but it just doesn't turn out that way
for reference types. If you'd agree with that, then perhaps I'm a big step
closer to thinking in C#.

Here's the improved code sample again, for your convenience:

namespace ImprovedPropertyExample
{
public class FloatRgba
{
public float r = 1.0f;
public float g = 1.0f;
public float b = 1.0f;
public float a = 1.0f;

public FloatRgba()
{
}

public FloatRgba(float r, float g, float b, float a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}

public void Invert()
{
r = 1.0f - r;
g = 1.0f - g;
b = 1.0f - b;
a = 1.0f - a;
}
}

public class MaterialBefore
{
public FloatRgba diffuseColor = new FloatRgba();
public FloatRgba DiffuseColor
{
get { return diffuseColor; }
set { diffuseColor = value; }
}
}

public class MaterialAfter
{
public float diffuseR = 1.0f;
public float diffuseG = 1.0f;
public float diffuseB = 1.0f;
public float diffuseA = 1.0f;

public FloatRgba DiffuseColor
{
get
{
return new FloatRgba(diffuseR, diffuseG, diffuseB,
diffuseA);
}
set
{
diffuseR = value.r;
diffuseG = value.g;
diffuseB = value.b;
diffuseA = value.a;
}
}
}

class Program
{
static void Main(string[] args)
{
MaterialBefore materialBefore = new MaterialBefore();
MaterialAfter materialAfter = new MaterialAfter();

System.Console.WriteLine("materialBefore initial: " +
materialBefore.diffuseColor.r.ToString());
System.Console.WriteLine("materialAfter initial: " +
materialAfter.diffuseR.ToString());

materialBefore.DiffuseColor.Invert();
materialAfter.DiffuseColor.Invert();

System.Console.WriteLine("materialBefore final: " +
materialBefore.diffuseColor.r.ToString());
System.Console.WriteLine("materialAfter final: " +
materialAfter.diffuseR.ToString());
}
}
}

Thanks again,

j
Nov 17 '05 #7

public FloatRgba DiffuseColor
{
get
{
return new FloatRgba(diffuseR, diffuseG, diffuseB,
diffuseA);
}
set
{
diffuseR = value.r;
diffuseG = value.g;
diffuseB = value.b;
diffuseA = value.a;
}
}
}


I have to ask. You want properties to act as member variables, yet you are
writing your getter in a way that does not work like a member variable.
Would you write this code using member variables or would you have designed
it differently?
Nov 17 '05 #8
"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:uZ**************@TK2MSFTNGP10.phx.gbl...

public FloatRgba DiffuseColor
{
get
{
return new FloatRgba(diffuseR, diffuseG, diffuseB,
diffuseA);
}
set
{
diffuseR = value.r;
diffuseG = value.g;
diffuseB = value.b;
diffuseA = value.a;
}
}
}


I have to ask. You want properties to act as member variables, yet you are
writing your getter in a way that does not work like a member variable.
Would you write this code using member variables or would you have
designed it differently?


What you ask is basically what I am asking! I would love to see a way to
implement MaterialAfter.Diffuse.get such that its semantics work exactly
like that of MaterialBefore.Diffuse.get, but I don't see how that is
possible without MaterialAfter containing a FloatRgba to hold the diffuse
color.

In the MaterialBefore case, there is indeed a member variable to return, and
that's how I would naturally expect the code to be written.. The code could
have originally been authored that way and remained that way for years.
Something has happened, though, and the class had to be refactored into
MaterialAfter such that there is no member variable to return anymore. The
goal would be to keep the interfaces and semantics of MaterialBefore and
MaterialAfter identical, but I don't see anyway to accomplish that. That's
why I'm starting to believe that properties do nothing more to enhance data
encapsulation than do general methods.

I mentioned that I was reading "Programming C#, 4th Ed." by Jesse Liberty.
In my Chapter 4, there's a section called "Encapsulating Data with
Properties". In my printing, it's on page 97. The author claims "By
decoupling the class state from the method that accesses that state, the
designer is free to change the internal state of the object as needed. [...]
By decoupling and forcing the client to go through a method (or property),
the Time class can change how it manages its internal state without breaking
client code. Properties meet both goals: they provide a simple interface to
the client, appearing to be a member variable. They are implemented as
methods, however, providing the data-hiding required by good object-oriented
design [...]."

My experience with my example code leads me to believe the above claims are
false, at least when dealing with reference types. In the author's defense,
though, the example does use an int, which is a value type. However, the
author does not differentiate between the two in the book, which I found
misleading. Not knowing C# very well, I was inclined to believe the author
and assumed that there must be some reasonable way to make the
MaterialBefore and MaterialAfter interfaces work exactly the same. If there
is, I now believe that it is a much more involved code change that I would
have anticipated. I can imagine a solution where an interface is created
for FloatRgba, the concrete version of FloatRgba implements that interface,
and the DiffuseColor property returns a special class that also implements
the FloatRgba interface but is capable of modifying the underlying float
member values in the MaterialAfter object which returned it. Because of the
significant change to FloatRgba, I'm confident that this solution will
require extensive client code changes as well, which pretty much defeats the
purpose of trying to preserve the old interface.

j
Nov 17 '05 #9

"Jeff Grills" <jg***********@drivensnow.org> wrote in message
news:Oq**************@tk2msftngp13.phx.gbl...
"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:uZ**************@TK2MSFTNGP10.phx.gbl...

What you ask is basically what I am asking! I would love to see a way to
implement MaterialAfter.Diffuse.get such that its semantics work exactly
like that of MaterialBefore.Diffuse.get, but I don't see how that is
possible without MaterialAfter containing a FloatRgba to hold the diffuse
color.


Jeff,

If I understand you correctly, it's not possible - but I don't see that
that's anything to do with the encapsulation capabilities of properties.

Your MaterialBefore class had a contract with its caller - DiffuseColor
returned a reference to a mutable shared object that maintained the current
setting of that FloatRgba value. It was shared, so changes to the value were
immediately apparent to both caller and callee. Whether that was really the
intent of the original designer is another question.

Removing that FloatRgba value from the Material class breaks that contract
whatever way you look at it. Doesn't matter how the reference was
obtained - property, member variable or method. The change is inherently a
change in the semantics of the way your objects interact, and there's not
much any programming language can do about it.

And yes, the key here is that it is a reference type (and mutable) - that's
what makes the contract one of shared data, and consequent tight coupling.
So if you were designing the original MaterialBefore class you wouldn't do
it this way unless you were quite sure that was the semantics that was
really required. Once you've gone down that path, encapsulation isn't going
to help if you change your mind later.

---------
Nigel Norris

Nov 17 '05 #10
> My experience with my example code leads me to believe the above claims
are false, at least when dealing with reference types. In the author's
defense, though, the example does use an int, which is a value type.
However, the author does not differentiate between the two in the book,
which I found misleading. Not knowing C# very well, I was inclined to
believe the author and assumed that there must be some reasonable way to
make the MaterialBefore and MaterialAfter interfaces work exactly the
same. If there is, I now believe that it is a much more involved code
change that I would have anticipated. I can imagine a solution where an
interface is created for FloatRgba, the concrete version of FloatRgba
implements that interface, and the DiffuseColor property returns a special
class that also implements the FloatRgba interface but is capable of
modifying the underlying float member values in the MaterialAfter object
which returned it. Because of the significant change to FloatRgba, I'm
confident that this solution will require extensive client code changes as
well, which pretty much defeats the purpose of trying to preserve the old
interface.


While Nigels response is pretty much dead on, and I can't add much more, I
can suggest a way around your issue.

Design a derivative of FloatRgba which takes MaterialAfter and gets its
values from that. Then when thigns change in the FloatRgba it can change
your MaterialAfter directly. Its messy, but doable.
Nov 17 '05 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Christopher Jeris | last post by:
I am relatively new to JavaScript, though not to programming, and I'm having trouble finding the idiomatic JS solution to the following problem. I have a table with (say) fields f1, f2, f3. I...
3
by: John Baro | last post by:
I have a class as: public class a : { private float m_b; public float b { get {
4
by: Tony W | last post by:
Hi, I am trying to write a simple application to retrieve data from the Windows registry and insert it into textboxs on a windows form. So far I have one namespace containing two classess. ...
18
by: Janaka | last post by:
I'm having a discussion with my colleagues here on good programming standards. One thing we haven't agreed on is the use of properties in classes vs using member variables. Now everyone knows...
4
by: Mantorok | last post by:
Hi I have an ASP app which references a few static properties in some of the classes. I understand that you should use Session variables, but is it "possible" to have each session "not"...
8
by: dwok | last post by:
I have been wondering this for a while now. Suppose I have a class that contains some private member variables. How should I access the variables throughout the class? Should I use properties that...
11
by: Brent Ritchie | last post by:
Hello all, I have been using C# in my programming class and I have grown quite fond of C# properties. Having a method act like a variable that I can control access to is really something. As...
60
by: Dave | last post by:
I'm never quite sure whether to use "this." or not when referring to fields or properties in the same class. It obviously works just fine without it but sometimes I wonder if using this....
5
by: Doug | last post by:
Hi I have been told about the following code: private string boxLabel; public string BoxLabel {
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.