Nested classes

  • Thread starter Thread starter B0nj
  • Start date Start date
B

B0nj

I've got a class in which I want to implement a property
that operates like an indexer, for the various colors
associated with the class.
For instance, I want to be able to do 'set' operations like
MyClass.MyColors["Background"] = Color.Green
or, a 'get', such as
Color forecolor = MyClass.MyColors["Foreground"];
I want to use an indexer so I can take parameters, such
as the color type (e.g. "Foreground", "Background" etc.).
With a single member function I couldn't do this as I would have to
have GetColor and SetColor which seems a little bit kludgy, due
to the need to have a parameter.
However I don't want to use the indexer of the class itself
as 'MyClass["Background"] = Color.Green' hasn't really got
anything pertaining to the specific color property. Besides,
I may want to have more properties like this but color.
(I am actually using an enum rather than strings such as
"Background"/"Foreground", but you get the idea.)
So what I've done is implemented a separate 'nested'
class to provide the color property, and used its indexer
to get and set the various colors, which are then stored in an
array in the nested class.
I initially tried to make the nested class itself private, but the
color-setting property that is of the type of the nested class
public, but I got the error 'MyColors is less accessible than the
member that is of its type' error. I then of course had to make
the nested class public, presumably because the information
about its type and thus its interface has to be made available
to the client, but it's not the sort of class that the client should
be able to create an instance of, so I've declared its constructor
internal, so it can't be instantiated outside of the project.
But I am wondering if this is the best way to do it, or the right
use for nested classes - as the client can still see the nested class,
just can't instantiate it. I'm reasonably happy enough with this
prevention because it would generate a compile-time error, not
a runtime one, but I was wondering if there was a better way?
The aim really is to make the syntax for the color-setting functionality
as simple and intuitive to the client as possible.

Any ideas?
 
I don't see a need for a nested class. Personally, I only use them when
they are very specific to the parent class. They are usually private or
internal when I do use them.

In your situation, I would implement a more generic (reusable) solution
and create a class that inherits from DictionaryBase to represent the
colors. Something like this...

public class ColorCollection : DictionaryBase
{
public Color this[string colorName]
{
get{ return (Color)this.Dictionary[colorName]; }
set{ /**/ }
}

etc...
}

Then your class in question would have a ColorCollection property:

public ColorCollection Colors
{
get{ return _colors; }
}

Clients of this class would use the property like this:

Color bg = myClass.Colors["Background"];
myClass.Colors["Foreground"] = Color.Black;


Regards,
-Jeff
I've got a class in which I want to implement a property
that operates like an indexer, for the various colors
associated with the class.
For instance, I want to be able to do 'set' operations like
MyClass.MyColors["Background"] = Color.Green
or, a 'get', such as
Color forecolor = MyClass.MyColors["Foreground"];
I want to use an indexer so I can take parameters, such
as the color type (e.g. "Foreground", "Background" etc.).
With a single member function I couldn't do this as I would have to
have GetColor and SetColor which seems a little bit kludgy, due
to the need to have a parameter.
However I don't want to use the indexer of the class itself
as 'MyClass["Background"] = Color.Green' hasn't really got
anything pertaining to the specific color property. Besides,
I may want to have more properties like this but color.
(I am actually using an enum rather than strings such as
"Background"/"Foreground", but you get the idea.)
So what I've done is implemented a separate 'nested'
class to provide the color property, and used its indexer
to get and set the various colors, which are then stored in an
array in the nested class.
I initially tried to make the nested class itself private, but the
color-setting property that is of the type of the nested class
public, but I got the error 'MyColors is less accessible than the
member that is of its type' error. I then of course had to make
the nested class public, presumably because the information
about its type and thus its interface has to be made available
to the client, but it's not the sort of class that the client should
be able to create an instance of, so I've declared its constructor
internal, so it can't be instantiated outside of the project.
But I am wondering if this is the best way to do it, or the right
use for nested classes - as the client can still see the nested class,
just can't instantiate it. I'm reasonably happy enough with this
prevention because it would generate a compile-time error, not
a runtime one, but I was wondering if there was a better way?
The aim really is to make the syntax for the color-setting functionality
as simple and intuitive to the client as possible.

Any ideas?
 
Switch to VB.NET? ;)

The problem is not with nested classes per se, you get the same problem if
you un-nest the class. The limitation is that the type of a property must
be "as accessible" as the property itself. Found this in 3.5.4:
http://tinyurl.com/33jec "The type of a property must be at least as
accessible as the property itself." Same is true for the return type and
formal param types of methods, operators, etc.

Seems to me if the only thing public in your public nested class is this
indexer, then that's really very little extra baggage in the public view of
your assembly. I don't know what else could be done cleaner.

Brad Williams
 
Hi Jeff,

If you don't use nested classes you have to decalare some events for
collection changes. Presonally I find this really annoying when ot comes for
collections which are used only in one particular class. In this casses I
prefer nested classes. This ofcourse makes the main class pretty big. This
inconvenience partially can be handled using regions. In C# 2 I believe
partial classes is going to be the solution for that since it looks like c#
wnat introduce the *friend* modifier.

Using nested classes is personal choice ofcourse.

So, B0nj, I'd suggest using interfaces.

declare a public interface
public interface IColorCollection
{
Color this[string item]
{
get;
set;
}
}

2. declare private nested class that implements the interface
class MyClass
{
//nested class
private class ColorCollection: DictionaryBase, IColorCollection
{
public ColorCollection(MyClass owner)
{
//owner is going to be used to access outer class members
}

//implementing interface member
public Color this[string item]
{
get
{
return (Color)base.Dictionary[item];
}
set
{
base.Dictionary[item] = value;
}
}


}

//the property returns the interface, which is public
public IColorCollection Colors
{
get
{
return colorCollection;
}
}
}

--
HTH
Stoitcho Goutsev (100) [C# MVP]


Jeff Mastry said:
I don't see a need for a nested class. Personally, I only use them when
they are very specific to the parent class. They are usually private or
internal when I do use them.

In your situation, I would implement a more generic (reusable) solution
and create a class that inherits from DictionaryBase to represent the
colors. Something like this...

public class ColorCollection : DictionaryBase
{
public Color this[string colorName]
{
get{ return (Color)this.Dictionary[colorName]; }
set{ /**/ }
}

etc...
}

Then your class in question would have a ColorCollection property:

public ColorCollection Colors
{
get{ return _colors; }
}

Clients of this class would use the property like this:

Color bg = myClass.Colors["Background"];
myClass.Colors["Foreground"] = Color.Black;


Regards,
-Jeff
I've got a class in which I want to implement a property
that operates like an indexer, for the various colors
associated with the class.
For instance, I want to be able to do 'set' operations like
MyClass.MyColors["Background"] = Color.Green
or, a 'get', such as
Color forecolor = MyClass.MyColors["Foreground"];
I want to use an indexer so I can take parameters, such
as the color type (e.g. "Foreground", "Background" etc.).
With a single member function I couldn't do this as I would have to
have GetColor and SetColor which seems a little bit kludgy, due
to the need to have a parameter.
However I don't want to use the indexer of the class itself
as 'MyClass["Background"] = Color.Green' hasn't really got
anything pertaining to the specific color property. Besides,
I may want to have more properties like this but color.
(I am actually using an enum rather than strings such as
"Background"/"Foreground", but you get the idea.)
So what I've done is implemented a separate 'nested'
class to provide the color property, and used its indexer
to get and set the various colors, which are then stored in an
array in the nested class.
I initially tried to make the nested class itself private, but the
color-setting property that is of the type of the nested class
public, but I got the error 'MyColors is less accessible than the
member that is of its type' error. I then of course had to make
the nested class public, presumably because the information
about its type and thus its interface has to be made available
to the client, but it's not the sort of class that the client should
be able to create an instance of, so I've declared its constructor
internal, so it can't be instantiated outside of the project.
But I am wondering if this is the best way to do it, or the right
use for nested classes - as the client can still see the nested class,
just can't instantiate it. I'm reasonably happy enough with this
prevention because it would generate a compile-time error, not
a runtime one, but I was wondering if there was a better way?
The aim really is to make the syntax for the color-setting functionality
as simple and intuitive to the client as possible.

Any ideas?
 
Brad,
It completely make sense to me. If the property is public that means
evetybody can use it, but how you can use it if the type of the property is
not accessible. The type of the property has to have the same visibilty or
to be more visible the the property itself. The same goes for method
parameters, and return values. Actually it goes for each public member.
 
Hi Stoitcho,

You are right about having to wire up the collection events - definitely
a pain, but to me it's worth the effort if I can get a reusable class
out of it.

Thanks for sharing your interface solution - interesting idea. How do
you use this solution to get around wiring the events? I noticed your
ColorCollection constructor takes a reference to the parent class. Do
you use this reference to notify the parent class of changes to the
collection? Do you make direct updates to the parent class?

Regards,
-Jeff
 
The reason behind the question, is that
the whole point of encapsulation is that functionality
is not exposed. Admittedly there would not be mileage
in going to great lengths to 'shield' it in this case,but i like
the sound of the interface idea.


Stoitcho Goutsev (100) said:
Brad,
It completely make sense to me. If the property is public that means
evetybody can use it, but how you can use it if the type of the property is
not accessible. The type of the property has to have the same visibilty or
to be more visible the the property itself. The same goes for method
parameters, and return values. Actually it goes for each public member.
--

Stoitcho Goutsev (100) [C# MVP]


Brad Williams said:
Switch to VB.NET? ;)

The problem is not with nested classes per se, you get the same problem if
you un-nest the class. The limitation is that the type of a property must
be "as accessible" as the property itself. Found this in 3.5.4:
http://tinyurl.com/33jec "The type of a property must be at least as
accessible as the property itself." Same is true for the return type and
formal param types of methods, operators, etc.

Seems to me if the only thing public in your public nested class is this
indexer, then that's really very little extra baggage in the public view of
your assembly. I don't know what else could be done cleaner.

Brad Williams
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top