William
William

Reputation: 1395

List of various slightly different generic objects

I am merging some code bases into one and am trying to figure out a clever way to merge some slightly different generic objects into a list that builds some of the UI for filtering.

I have many Manager objects that produce and manage ResultSets that are built on top of some of the application base classes.

Any ideas would be great. I am trying not to refactor old deep code as much as possible.

CityManager is something like

   ImAFilterSetManager<ImAFilterSetBase<CityBase>>

and ChainManger is something like

   ImAFilterSetManager<ImAFilterSetBase<ChainBase>>

The Manager executes the Initialize and returns a ImAFilterSetBase and wires the handler.

Is there a way to cast to something like below?

ImAFilterSetManager<ImAFilterSetBase<object>>

Execution code

      List<object> filters = new List<object>() { 
                        new CityManager(),
                        new ChainManager(), }

        //(XXXX as  object fails)
        foreach (ImAFilterSetManager<ImAFilterSetBase<XXXX>> filter in filters) 
        {
               var newFilter = filter.Initialize(_Client);

               filter.OnResultsChanged += filterResults_Handler;
        }

It does seem if use dyanmic i can Initialize (or at least it compliles and runs, havent tried much else) but I'm a little worried that would be bad form or cause side effects.

foreach (dynamic filter in filters) 
{           
    var newFilter = filter.Initialize(_Client);
}

Interfaces for reference ( generic I is a ImAFilterSetBase(CityBase) and generic C would be CityBase or ChainBase class )

public interface ImAFilterSetManager<I>
        {
                event EventHandler<ResultSetArgs> OnResultsChanged;

                I Initialize(IClient client);
        }

        public interface ImAFilterSetBase<C>
        {
                string FilterName { get; set; }

                List<C> Filter { get; set; }
        }

Upvotes: 1

Views: 93

Answers (2)

jherax
jherax

Reputation: 5267

You may think in the Liskov Substitution Principle (SOLID), so a good way is relate the objects via an interface:

//defines the contract
public interface IObjectBase {
    //add signatures
}

class CityBase : IObjectBase /*, IAnotherBaseA */ {
    //implementation
}

class ChainBase : IObjectBase /*, IAnotherBaseB */ {
    //implementation
}

Now we are going to create a constraint for the ImAFilterSetBase and rename it to AFilterSetBase

public abstract class AFilterSetBase<T> where T : IObjectBase /*, new() */ {
        public string FilterName { get; set; }
        public IList<T> Filters { get; set; }
}

I am going to redefine the interface ImAFilterSetManager and rename it to IFilterSetManager

public interface IFilterSetManager {
    event EventHandler<ResultSetArgs> OnResultsChanged;
    AFilterSetBase<IObjectBase> Initialize(IClient client);
}

Now we can create the classes that implements IFilterSetManager:

public class CityManager : IFilterSetManager {
    public AFilterSetBase<IObjectBase> Initialize(IClient client) {
        //TODO: implementation
        throw new NotImplementedException();
    }
}

//other classes that implements IFilterSetManager 
class ChainManager : IFilterSetManager {
    public AFilterSetBase<IObjectBase> Initialize(IClient client) {
        throw new NotImplementedException();
    }
}

Finally, in the end-class we can create the list as follow:

static void Main() {
    IClient _client;
    //_client = new ...

    var filters = new List<IFilterSetManager>() {
        new CityManager(),
        new ChainManager()
    };

    foreach (var item in filters) {
        var newFilter = item.Initialize(_client);
    }
}

IMPLEMENTATION

An example implementation for CityManager could be as follow:

class CityFilter : AFilterSetBase<IObjectBase> {
    public CityFilter(string filterName) {
        this.FilterName = filterName;
        this.Filters = new List<IObjectBase>();
    }
}

public class CityManager : IFilterSetManager {
    public AFilterSetBase<IObjectBase> Initialize(IClient client) {
        var item = new CityFilter("City Filters");
        item.Filters.Add(new CityBase());
        return item;
    }
}

And then we can test it:

    static void Main(string[] args) {
        IClient _client;
        _client = null;

        var filters = new List<IFilterSetManager>() {
            new CityManager(),
            new ChainManager()
        };

        foreach (var item in filters) {
            var newFilter = item.Initialize(_client);
            System.Console.WriteLine("Filter name: " + newFilter.FilterName);
            System.Console.WriteLine("Filters added: " + newFilter.Filters.Count);
        }

        System.Console.ReadLine();
    }

Upvotes: 0

zmbq
zmbq

Reputation: 39069

In C#, Generic<A> and Generic<B> are not related, unless you make them related. Create another non-generic class (or interface) - FilterSetManager, and have all your ImAFilterSetManager<T> derive from that, or implement that.

Then you can have a List<FilterSetManager>.

Upvotes: 2

Related Questions