How to avoid duplicating code for accessing properties WITHOUT using reflection - c#

I have these structure
class A : IFoo {
Foo(){
//do something
}
IList<B> Bs {get;set;}
IList<C> Cs {get;set;}
}
class B : IFoo {
Foo(){
//do something
}
IList<D> Ds {get;set;}
}
class C : IFoo {
Foo(){
//do something
}
}
class D : IFoo {
Foo(){
//do something
}
}
class Helper{
Bar(A a){
a.Foo();
Bar(a.Bs);
Bar(a.Cs);
}
Bar(IList<B> bs)
{
foreach(var b in bs)
{
Bar(b);
}
}
Bar(B b)
{
b.Foo();
Bar(b.Ds);
}
Bar(IList<C> cs)
{
foreach(var c in cs)
{
Bar(c);
}
}
Bar(C c)
{
c.Foo();
}
Bar(IList<D> ds)
{
foreach(var d in ds)
{
Bar(d);
}
}
Bar(D d)
{
d.Foo();
}
}
interface IFoo {
void Foo();
}
As you see a lot of code is repeated in Helper class (i.e. method Bar) for different types of A,B,C,IList<A>,IList<B>,IList<C>. Also when a new list property is added to the classes I need to get back and change the Helper class which is somehow in contradiction with Open/Close principal.
I know how to use Reflection to solve the issue, but I was searching for another smart and neat way to solve this issue and not using Reflection.
I am free to add new Interfaces but not base class
Any suggestion will be appreciated

If you want to keep the OPEN/CLOSE principle intact, you can go with something like this -
Each class will extend as necessary.
New class does not need to modify old class- Helper. So the implementation becomes somewhat like the one below. NO matter how many class you add, each class is responsible for there own Foo and Bar implementation.
Example -
public interface IFoo
{
void Foo();
void Bar();
}
public abstract class BaseFoo : IFoo
{
public virtual void Foo()
{
//do nothing
}
public virtual void Bar()
{
//do nothing
}
}
public class A : BaseFoo //replace with IFoo if you do not want the base class, in that case implement both methods
{
IList<B> Bs { get; set; }
IList<C> Cs { get; set; }
public override void Bar()
{
base.Bar();
foreach (var b in Bs)
{
b.Bar();
}
foreach (var c in Cs)
{
c.Bar();
}
}
}
public class B : BaseFoo //replace with IFoo if you do not want the base class, in that case implement both methods
{
IList<D> Ds { get; set; }
public override void Bar()
{
base.Bar();
foreach (var d in Ds)
{
d.Bar();
}
}
}
public class C : BaseFoo //replace with IFoo if you do not want the base class, in that case implement both methods
{
}
public class D : BaseFoo //replace with IFoo if you do not want the base class, in that case implement both methods
{
}
public static class Helper
{
public static void Bar(params IFoo[] foos)
{
foreach (var foo in foos)
{
foo.Bar();
}
}
}

Assuming that method Foo() exists on the IFoo interface, and given that your Bar methods for B, C and D do nothing other than invoke the Foo implementation for the class, why not remove the Bar overloads altogether (since the dependency coupling is only to the interface method Foo())
Your looped method becomes (renamed from Bar(IList<B/C/D> bs)):
void InvokeFoo(IEnumerable<IFoo> foos)
{
foreach(var foo in foos)
{
foo.Foo();
}
}
Which would be invoked:
Bar(A a){
a.Foo();
InvokeFoo(a.Bs);
InvokeFoo(a.Cs);
}
Edit
The above answer misses the fact that classes (e.g. B) can have child collections, through which you also need to iterate. If these child collections are arbitrary in number (e.g. A has 2 such collections, B has 1, and C and D none), and given your statement that you can't modify the actual classes A, B, C etc, you could specify a 'special' action to be taken for each class. This would be a naive implementation, which only will work for one level of recursion (which is what you have):
class Helper
{
public void Bar(A a)
{
a.Foo();
InvokeFoo(a.Bs, foo => InvokeFoo(((B)foo).Ds));
InvokeFoo(a.Cs);
}
void InvokeFoo(IEnumerable<IFoo> foos, Action<IFoo> childAction = null)
{
foreach (var foo in foos)
{
foo.Foo();
childAction?.Invoke(foo);
}
}
}
Making this more generic / Recursive
Since it seems you aren't allowed to modify the classes (only the helper), violation of the Open+Closed principal of SOLID seems inevitable (since the navigation is done by an external observer).
As a poor man's form of polymorphicism, and to keep the 'smell' in one place, what you could do is provide an overload to assist each type walk it's children. The default behaviour (as per my first code) is simply to invoke Foo, if no type is found:
class Helper
{
private static readonly IDictionary<Type, Action<IFoo>> SpecialClassActions
= new Dictionary<Type, Action<IFoo>>
{
// Provide special handling for walking classes which have children
{
typeof(A),
foo =>
{
InvokeChildFoo(((A)foo).Bs);
InvokeChildFoo(((A)foo).Cs);
}
},
{
typeof(B),
foo =>
{
InvokeChildFoo(((B)foo).Ds);
}
}
// Add more handling here as new subtypes are added
};
static void WalkFooHierarchy(IFoo foo)
{
foo.Foo();
Action<IFoo> specialChildAction;
if (SpecialClassActions.TryGetValue(foo.GetType(), out specialAction))
{
specialChildAction(foo);
}
}
// Replaces your Bar(IList<> ..) methods
static void InvokeChildFoo(IEnumerable<IFoo> foos)
{
foreach (var foo in foos)
{
WalkFooHierarchy(foo);
}
}
You then kick the process off by starting to walk from your root level object:
public void Bar(A a)
{
Helper.WalkFooHierarchy(a);
}

Based on priceless suggestions and solutions I ended up like below, this solution is Open/Closed and by adding another list only that class should be changed and all of the overloads of Bar in Helper class is removed.
class Program
{
static void Main(string[] args)
{
Helper.Bar(new A());
}
}
public class A : IFoo, IMap
{
public A()
{
Cs = new List<C> { new C(), new C() };
Bs = new List<B> { new B(), new B() };
}
public void Foo()
{
Console.WriteLine("A");
}
public List<B> Bs { get; set; }
public List<C> Cs { get; set; }
public List<Func<dynamic, List<IFoo>>> Map()
{
return this.CreateMap()
.Then(x => ((List<B>)x.Bs).ToList<IFoo>())
.Then(x => ((List<C>)x.Cs).ToList<IFoo>());
}
}
public class B : IFoo, IMap
{
public B()
{
Ds = new List<D> { new D(), new D() };
}
public void Foo()
{
Console.WriteLine("B");
}
public List<Func<dynamic, List<IFoo>>> Map()
{
return this.CreateMap()
.Then(x => ((List<D>)x.Ds).ToList<IFoo>());
}
public List<D> Ds { get; set; }
}
public class C : IFoo, IMap
{
public void Foo()
{
Console.WriteLine("C");
}
public List<Func<dynamic, List<IFoo>>> Map()
{
return this.CreateMap();
}
}
public class D : IFoo, IMap
{
public void Foo()
{
Console.WriteLine("D");
}
public List<Func<dynamic, List<IFoo>>> Map()
{
return this.CreateMap();
}
}
public static class Mapper
{
public static List<Func<dynamic, List<IFoo>>> CreateMap(this IFoo item)
{
return new List<Func<dynamic, List<IFoo>>>();
}
public static List<Func<dynamic, List<IFoo>>> Then(this List<Func<dynamic, List<IFoo>>> list, Func<dynamic, List<IFoo>> expression)
{
list.Add(expression);
return list;
}
}
public class Helper
{
public static void Bar(dynamic obj)
{
obj.Foo();
var map = obj.Map();
if (map != null)
{
foreach(var item in map)
{
var lists = item(obj);
foreach(var list in lists)
{
Bar(list);
}
}
}
}
}
public interface IFoo
{
void Foo();
}
public interface IMap
{
List<Func<dynamic, List<IFoo>>> Map();
}
#brainlesscoder, #StuartLC : since your solutions are also correct I only up-vote them and I don't tag any of the solutions as answer to keep this thread open and might someone else suggests a better solution than us. If you think my solution is also good please up-vote ;)

This seems to me to be the most straight-forward way to do this:
public static class Helper
{
public static void Bar<F>(F f) where F : IFoo
{
f.Foo();
Helper.Bar((f as A)?.Bs);
Helper.Bar((f as A)?.Cs);
Helper.Bar((f as B)?.Ds);
}
public static void Bar<F>(IList<F> fs) where F : IFoo
{
if (fs != null)
{
foreach (var f in fs)
{
Helper.Bar(f);
}
}
}
}
Now if the rest of the code is defined like this:
public class A : IFoo
{
public void Foo() { Console.Write("A"); }
public IList<B> Bs { get; set; } = new List<B>() { new B(), new B(), };
public IList<C> Cs { get; set; } = new List<C>() { new C(), new C(), };
}
public class B : IFoo
{
public void Foo() { Console.Write("B"); }
public IList<D> Ds { get; set; } = new List<D>() { new D(), new D(), };
}
public class C : IFoo
{
public void Foo() { Console.Write("C"); }
}
public class D : IFoo
{
public void Foo() { Console.Write("D"); }
}
public interface IFoo
{
void Foo();
}
...then you can run this:
var a = new A();
var b = new B();
var c = new C();
var d = new D();
Helper.Bar(a);
Helper.Bar(b);
Helper.Bar(c);
Helper.Bar(d);
...and you get ABDDBDDCCBDDCD as expected as the output.

Related

Pattern to avoid the need for Downcasting/Reflection

Suppose I have two implementations of a base class:
public class Base {
public string Stringify() { return "I am a member of base class"; }
}
public class A : Base {
public void DoAThing() {...};
}
public class B : Base {
public void DoBThing(int anInteger) {...};
}
Suppose I want to put many instances of Base in a list, so that I can loop over them and call Stringify() on each, and make use of their shared functionality.
static void Main(string[] args)
{
A thing1 = new A();
B thing2 = new B();
B thing3 = new B();
List<Base> list = new List<Base> {thing1, thing2, thing3};
foreach(Base base in list) { Console.WriteLine(base.Stringify()); }
}
Now suppose there are many many Base objects, such that maintaining the individual thing references to each one is not realistic. Would there be any way, via only the list, to regain the DoAThing() or DoBThing() functionality that is lost by the abstraction without having to use explicit downcasting and reflection?
This feels like it would be a common enough occurance, so I am wondering if there is a design flaw or established pattern I am missing here that would help in this situation.
If you debug, you can notice every object of the list mantains its' class.
This way:
class Program
{
static void Main(string[] args)
{
A thing1 = new A();
B thing2 = new B();
B thing3 = new B();
List<Base> list = new List<Base> { thing1, thing2, thing3 };
foreach (Base bas in list) {
Console.WriteLine(bas.Stringify());
if(bas is A)
{
((A)bas).DoAThing();
}
else if (bas is B)
{
((B)bas).DoBThing(1);
}
else
{
//IDK
}
}
}
}
public abstract class Base
{
public string Stringify() { return "I am a member of base class"; }
}
public class A : Base
{
public void DoAThing()
{
}
}
public class B : Base
{
public void DoBThing(int anInteger)
{
}
}

Is this the only way to have the functionality of abstract static methods?

I'm working on a framework right now and the motto is "no redundancy" and "I don't want to know the vendor specifics" so most things are handled through Interfaces and Generic classes. Now I had the situation where I have an abstract class that wants to match things depending on it's own Enum variable se but it shouldn't have to know how the vendor provides a relatable variable to be matched to se. The vendor could have decided an integer, an Enum or a string would be the best to save that information but honestly I don't want to know.
So I thought well no problem have an abstract static method that must be provided by every implementation of a wrapper to compare se with the vendor specific way of saving that information.
//The original version I wanted to be possible
public abstract class AbstractGenericClass<TWrapper<T>, T> where TWrapper : AbstractGenericWrapper<T> {
protected TWrapper tWrapper;
//our SomeEnum se is somehow relatable to every T
//but we don't want to know how
protected SomeEnum se = ...;
//called on Start
public void Start() {
List<T> ts = FindObjectsOfType<T>;
foreach (T t in ts) {
if(T.Compare(t, this.se)) {
tWrapper = new TWrapper(t);
}
}
}
}
public abstract class AbstractGenericWrapper<T> {
T _t;
public AbstractGenericWrapper(T t) {
_t = t;
}
public static abstract bool Compare(T t, SomeEnum someEnum);
}
public class ConcreteNongenericWrapper : AbstractGenericWrapper<VendorSpecificImplementation> {
public static bool Compare(VendorSpecificImplementation t, SomeEnum someEnum) {
return t.vendorVariable.toLower().Equals(Enum.GetValues(typeof(someEnum), someEnum));
}
}
public class OtherConcreteNongenericWrapper : AbstractGenericWrapper<OtherVendorSpecificImplementation> {
public static bool Compare(OtherVendorSpecificImplementation t, SomeEnum someEnum) {
return t.otherVendorVariable % 3 == (int) someEnum;
}
}
public class SomeImplementation {
public static void main() {
AbstractGenericClass<ConcreteNongenericWrapper<ConcreteNongeneric>, ConcreteNongeneric> foo
= new AbstractGenericClass<ConcreteNongenericWrapper<ConcreteNongeneric>, ConcreteNongeneric>();
AbstractGenericClass<OtherConcreteNongenericWrapper<OtherConcreteNongeneric>, OtherConcreteNongeneric> bar
= new AbstractGenericClass<OtherConcreteNongenericWrapper<OtherConcreteNongeneric>, OtherConcreteNongeneric>();
foo.Start();
bar.Start();
}
}
I found out that that isn't possible and I wanted to know if this version down below is the best/only way of doing it? It has redundancy and I don't like it and it is longer.
//An attempt at a solution:
public abstract class AbstractGenericClass<TWrapper<T>, T> where TWrapper : AbstractGenericWrapper<T> {
protected TWrapper tWrapper;
//our SomeEnum se is somehow relatable to every T
//but we don't want to know how
protected SomeEnum se = ...;
//called on start
public abstract void Start();
}
public abstract class AbstractGenericWrapper<T> {
T _t;
public AbstractGenericWrapper(T t) {
_t = t;
}
}
public class ConcreteNongenericClass : AbstractGenericClass<VendorSpecificImplementation> {
//called on start
public override void Start() {
List<VendorSpecificImplementation> ts = FindObjectsOfType<VendorSpecificImplementation>;
foreach (VendorSpecificImplementation t in ts) {
if(t.vendorVariable.toLower().Equals(Enum.GetValues(typeof(someEnum), someEnum))) {
tWrapper = new ConcreteNongenericWrapper(t);
}
}
}
}
public class ConcreteNongenericWrapper : AbstractGenericWrapper<VendorSpecificImplementation> {
}
public class OtherConcreteNongenericClass : AbstractGenericClass<OtherVendorSpecificImplementation> {
//called on start
public void Start() {
List<OtherVendorSpecificImplementation> ts = FindObjectsOfType<OtherVendorSpecificImplementation>;
foreach (OtherVendorSpecificImplementation t in ts) {
if(t.otherVendorVariable % 3 == (int) someEnum) {
tWrapper = new OtherConcreteNongenericWrapper(t);
}
}
}
}
public class OtherConcreteNongenericWrapper : AbstractGenericWrapper<OtherVendorSpecificImplementation> {
}
public class SomeImplementation {
public static void main() {
AbstractGenericClass<ConcreteNongenericWrapper<ConcreteNongeneric>, ConcreteNongeneric> foo
= new AbstractGenericClass<ConcreteNongenericWrapper<ConcreteNongeneric>, ConcreteNongeneric>();
AbstractGenericClass<OtherConcreteNongenericWrapper<OtherConcreteNongeneric>, OtherConcreteNongeneric> bar
= new AbstractGenericClass<OtherConcreteNongenericWrapper<OtherConcreteNongeneric>, OtherConcreteNongeneric>();
foo.Start();
bar.Start();
}
}
Thank you very much for your time and help!

Array of inherited from generic types

Code to demonstrate the problem:
static void Main(string[] args)
{
var a = new A();
var b = new B();
Base<>[] all = new Base<>[] { a, b }; // doesn't work
}
class Base<T>
{
public string Caption { get { return typeof(T).ToString(); } }
}
class A : Base<A> { }
class B : Base<B> { }
Perhaps I went the wrong direction. Idea was to move Caption into base class (Base become generic). Non-generic version works without problems:
var all = new Base[] { a, b }; // no problems for as long as Base is not generic
There's no Type<?> in C# - you always have to specify a concrete generic type.
The only way around this is to make Base<T> inherit a non-generic base-class, or implement a non-generic interface. You could then use that as the type of the array.
EDIT:
In your case this is extremely simple, since the part of the interface you want doesn't include the generic type argument. So you can simply do either:
public abstract class Superbase
{
public abstract string Caption { get; }
}
public class Base<T>: Superbase
{
public override string Caption { get { return typeof(T).Name; } }
}
Or, using an interface:
public interface IBase
{
string Caption { get; }
}
public class Base<T>: IBase
{
public string Caption { get { return typeof(T).Name; } }
}
Your array would then be Superbase[] or IBase[], respectivelly. In both cases, you can see that I'm not actually providing an implementation - both the declarations are "abstract", in a sense.
In general, I'm trying to keep the non-generic stuff in a non-generic base class, rather than stuffing it in the derived generic classes. It just feels more clean :)
based on #Luaan ideea, here is an implementation:
class Program
{
static void Main(string[] args)
{
var a = new A();
var b = new B();
var arr = new Base[] { a, b};
foreach (var obj in arr)
Console.WriteLine(obj.Caption);
Console.ReadKey();
}
}
public class Base<T> : Base
{
public override string Caption
{
get { return typeof (T).ToString(); }
}
}
public class A : Base<A> { }
public class B : Base<B> { }
public abstract class Base
{
public abstract string Caption { get; }
}
Instead of trying to use inheritance (which will lead to more problems down the line), use an extension method instead:
public interface IClassAORClassB {}
class A : IClassAORClassB { }
class B : IClassAORClassB { }
public static class Captions
{
public static string Caption<T>(this T obj) where T : IClassAORClassB
{
return obj.GetType().ToString();
}
}
static void Main(string[] args)
{
var a = new A();
var b = new B();
var all = new IClassAORClassB[] { a, b }; // works just fine
Console.WriteLine(all[0].Caption()); // prints A
Console.WriteLine(all[1].Caption()); // prints B
}

Accessing a function in polymorphism

There are 3 classes A,B,C . Classes B and C inherit from A.
Class B and C have a function - func1() ,A doesnt.
I have a list<A> OB where every object in it is eaither B or C.
I want to access func1 by OB[0].Func1().
How can i do this?
Thank you!
You're trying to call method func1 on class A, where A does not define it? You can't. You can make Func1 abstract within A if you want to do that.
abstract class A
{
public abstract Func1();
}
class B : A
{
public override Func1()
{
MessageBox.Show("Hello World");
}
}
class C : A
{
public override Func1()
{
MessageBox.Show("Goodbye World");
}
}
The fact that Func1 is abstract means that you can't instantiate A directly, but you can instantiate B.
var listOfA = new List<A>();
listOfA.Add(new B());
listOfA.Add(new C());
listOfA[0].Func1(); // hello world
listOfA[1].Func1(); // goodbye world
You could make Func1 defined as virtual in A instead of setting it as abstract, but I recommend you do not because this will introduce a reversed Refused Bequest design smell.
Add the method to class A as virtual, and make B and C override it:
public class A
{
public virtual void Foo()
{
}
}
public class B : A
{
public override void Foo()
{
}
}
public class C : A
{
public override void Foo()
{
}
}
If it doesn't make sense put func1() or can't change class A you can create a Interface that has func1() and have just class B and C implement that interface. Then when you need to call func1() cast your objects to that interface using the as operator. When using the as operator no exception is thrown if the cast fails.
public interface MyInterface
{
void func1();
}
public class B : MyInterface
{
public func1() {...}
....
}
public class C : MyInterface
{
public void func1() {...}
....
}
//example of calling func1()
List<A> list = new List<A>(stuff);
foreach(A item in list)
{
MyInterface tmp = item as MyInterface;
if(tmp != null)
{
tmp.func1();
}
}
Abstract factory do the same thing you are looking for
i found this code on CodeProject
this might help you
//Let's define type of bread bases
public enum BreadBase
{
HotIndianMasalaBase,
PunjabiTadkaBase,
ItalianCheeseBase,
VeggieBase,
}
//This is a breadfactory where people visit to get their favorite bread bases
public interface BreadFactory
{
Bread GetBread(BreadBase BreadBase);
}
//The abstract bread
public interface Bread
{
void Bake();
}
//create concrete classes
public class HotIndianMasalaBread :Bread
{
public void Bake()
{
Console.WriteLine ("For you::Hotindian Masala base Bread.");
}
}
public class VeggieBread : Bread
{
public void Bake()
{
Console.WriteLine("For you::Veggie base Bread.");
}
}
public class ItalianCheeseBread : Bread
{
public void Bake()
{
Console.WriteLine("For you::Italian cheese base Bread.");
}
}
public class PunjabiTadkaBaseBread : Bread
{
public void Bake()
{
Console.WriteLine("For you::Punjabi tadka base bread.");
}
}
//Lets create bread factories aka concrete classes
public class AmericanBreadFactory :BreadFactory
{
public Bread GetBread(BreadBase BreadBase)
{
Bread vBread = null;
switch (BreadBase)
{
case BreadBase.VeggieBase:
vBread = new VeggieBread();
break;
case BreadBase.ItalianCheeseBase:
vBread = new ItalianCheeseBread();
break;
}
return vBread;
}
}
public class IndianBreadFactory :BreadFactory
{
public Bread GetBread(BreadBase BreadBase)
{
Bread vBread = null;
switch (BreadBase)
{
case BreadBase.HotIndianMasalaBase:
vBread = new HotIndianMasalaBread();
break;
case BreadBase.PunjabiTadkaBase:
vBread = new PunjabiTadkaBaseBread();
break;
}
return vBread;
}
}
//lets order breads
class Program
{
static void Main(string[] args)
{
//example of abstract factory
AmericanBreadFactory vAmericanBread = new AmericanBreadFactory();
Bread vBread = vAmericanBread.GetBread(BreadBase.VeggieBase);
vBread.Bake();
//lets bak indian punjabi tadka bread
IndianBreadFactory vIndianBreadFactory = new IndianBreadFactory();
Bread vIndianBread = vIndianBreadFactory.GetBread(BreadBase.PunjabiTadkaBase);
vIndianBread.Bake();
}
}

Handling objects of different classes in a derived List<T> class

I have several classes (A, B, C, ...) that all use a List<AnotherClass> to store references to 'other' objects. But 'other' is different for each of the classes A, B, C.
So
Class A contains List<Class_X>
Class B contains List<Class_Y>
Class C contains List<Class_Z>
Instead of implementing Add / Delete / Search (etc) functions in A, B, C it seems logical to me to create a class ListRef<T> from List<T>
public class ListRef<T>: List<T>
{
protected ListRef<T> ListOfObjects = null;
protected string name = null;
public ListRef<T>
{
ListOfObjects = new ListRef<T>();
}
}
Using the code above (is this the right code for what I want?) I don't know how I can supply the right class (Class_X, Class_Y, Class_Z) replacing/specifying <T> in the constructor of each class (A, B, C) that will use ListRef.
In the constructor of class A I would like to write something like:
public A() : base<Class_X>
{
}
How can I specify from WITHIN class A what kind of objects need to be stored in ListOfObjects?
I prefer NOT to write
public A()
{
ListOfObjects = new ListRef<Class_X();
}
as I would like to have ListOfObjects declared private instead of protected
Inside Listref I JUST want to be able to Add, Delete, Search objects. So I'm not actually using those classes (Class_X, Class_Y, Class_Z).
currently I have
public class A
{
private List<Class_X> ListOfObjects = null;
A()
{
ListOfObjects = new List<Class_X>();
}
public void Add(string Name)
{
Class_X Object = new Class_X(Name);
ListOfObjects.Add(Object);
}
public void Delete(Class_X Object)
{
ListOfObjects.Remove(Object);
}
}
and the same kind of code for class B (using Class_Y) and for class C (using class_Z).
To me it seems logical to use ONE class ListRef to perform the Add and Delete operations and maintain the list for all classes I use.
(of course the real code is more complicated)
If I understand you question correctly, it sounds like what you want to do is create a group of classes A, B, C, etc.. that each manage a collection of some other type (X, Y, Z) - but you don't want to duplicate some of the list management logic across A, B, and C.
There are two different ways to achieve this.
First, the inheritance approach: you could give A, B, and C a common generic base class that is parameterized on the type of the item each will manage. Here's a code example:
public abstract class ABCBase<T>
{
protected IList<T> m_List = new List<T>();
// methods that manage the collection
// I chose to make the virtual so that derived
// classes could alter then behavior - may not be needed
public virtual void Add( T item ) { ... }
public virtual void Remove( T item ) { ... }
public virtual int Find( T item ) { ... }
}
public class A : ABCBase<X> { ... }
public class B : ABCBase<Y> { ... }
public class C : ABCBase<Z> { ... }
Second, is the composition approach: create a manager class for your colleciton that implements the operations on the child list, and aggregate that in each of A, B, and C:
public class ListManager<T>
{
private IList<T> m_List = new List<T>();
public void Add( T item ) { ... }
public void Remove( T item ) { ... }
public int Find( T item ) { ... }
}
public class A
{
public ListManager<X> ListOfX { get; protected set; }
public A() { ListOfX = new ListManager<X>(); }
}
public class B
{
public ListManager<Y> ListOfX { get; protected set; }
public B() { ListOfY = new ListManager<Y>(); }
}
public class C
{
public ListManager<Z> ListOfX { get; protected set; }
public C() { ListOfX = new ListManager<Z>(); }
}
You could also choose to mix both of these approaches - creating a list management class but also creating base class (or interface) for A, B, C - so that each exposes a consistent property ChildList (or some such) that consumers could use without always having to know the type actual types A, B, C.
Here is how I would recommend doing it...
public class ABC_Base<TChild>
{
public IEnumberable<TChild> Children { get; set; }
public void AddChild(TChild item)
{
}
public void RemoveChild(TChild item)
{
}
//etc
}
public class A : ABC_Base<X> // X is the type for your child
{
}
//Used like so...
A myA = new A();
myA.AddChild(new X());
// or if you are wanting to specify when created then this...
public class A<TChild> : ABC_Base<TChild>
{
}
//Used like so...
A myA = new A<X>();
A myOtherA = new A<Y>();
myA.Addchild(new X());
myOtherA.AddChild(new Y());
How about
public interface ISomeOtherClass
{
}
public class Class_X : ISomeOtherClass
{
}
public class Class_Y : ISomeOtherClass
{
}
public class BaseClass<T> where T : ISomeOtherClass
{
public ListRef<T> OtherObjects { get; set; }
}
public class A : BaseClass<Class_x>
{
}
public class B : BaseClass<Class_Y>
{
}
I hope I am correctly understanding your problem. Here is how I would do it:
interface ILetter<T>
{
IList<T> OtherObjects { get; }
}
class A : ILetter<Class_X>
{
public IList<Class_X> OtherObjects
{
get { /* ... */ }
}
}
class B : ILetter<Class_Y>
{
public IList<Class_X> OtherObjects
{
get { /* ... */ }
}
}
// etc...
With this interface you can be sure that each type has a public IList<T> property that you can use for any operations you wish.

Categories