Reputation: 9508
My application consist of server and client, which are independant. They communicate through objects created and modified by server. Client is provided with read-only interfaces of this objects. As far as I know, that's the correct way to keep encapsulation in OOP. See example:
// Client-side
interface IBox<T> where T : ITool
{
IEnumerable<T> Tools { get; }
}
interface ITool
{
void Use();
}
// Server-side
class Box : IBox<Tool>
{
public List<Tool> ToolList = new List<Tool>();
public IEnumerable<ITool> Tools
{
get { return ToolList; }
}
}
class Tool : ITool
{
string _msg = "default msg";
public string Msg
{
get { return _msg; }
set { _msg = value; }
}
public void Use()
{
Console.WriteLine("Tool used! Msg: {0}", _msg);
}
}
As you see, I have to use generics, because my objects form a hierarchy.
That looked nice, until I've decided to add a Room
class with interface IRoom
, which have to generalize not only IBox
, but ITool
too:
interface IRoom<B, T>
where B : IBox<T>
where T : ITool
{
IEnumerable<B> Boxes { get; }
}
class Room : IRoom<Box, Tool>
{
public List<Box> BoxList = new List<Box>();
public IEnumerable<Box> Boxes
{
get { return BoxList; }
}
}
Now, imagine that we have a Room
consist of not only boxes. I need at least 3 collections of absolutely different things there, which are collections of several types too. So, there must be a huge tree, and my root class become something like: Room : IRoom<Box, Tool1, Tool2, Tool3, Wardrobe, Coat, Jeans, Hat, Table, Computer, Book, Pen>
I'm not sure, that is right. So, I'm asking, what is true OOP-way of implementing my task? (with no reflection, breaking encapsulation, type casting or other bad tricks)
Upvotes: 2
Views: 2070
Reputation: 86630
Starting with the .NET Framework 4 and C# 4 you can use IEnumerable's covariance and just avoid using generics.
// Client-side
interface IBox
{
IEnumerable<ITool> Tools { get; }
}
interface ITool
{
void Use();
}
// Server-side
class Box : IBox
{
public List<Tool> ToolList = new List<Tool>();
public IEnumerable<ITool> Tools
{
get { return ToolList; } // With .NET 3.5 and earlier cast here is neccessary to compile
// Cast to interfaces shouldn't be so much of a performance penalty, I believe.
}
}
class Tool : ITool
{
string _msg = "default msg";
public string Msg
{
get { return _msg; }
set { _msg = value; }
}
public void Use()
{
Console.WriteLine("Tool used! Msg: {0}", _msg);
}
}
interface IRoom
{
IEnumerable<IBox> Boxes { get; }
}
class Room : IRoom
{
public List<Box> BoxList = new List<Box>();
public IEnumerable<IBox> Boxes
{
get { return BoxList; } // and here...
}
}
Covariance and contravariance in generics described here: http://msdn.microsoft.com/en-us/library/dd799517.aspx
Upvotes: 2