views:

126

answers:

1

Hi everyone,

I have say a dozen types T which inherit from EntityObject and IDataObject. I have generic the following interface

IDataManager<T> where T : EntityObject, IDataObject ...

I have also base class for data managers

BaseDataManager<T> : IDataManager<T> where T : EntityObject, IDataObject ....

And i have particular classes

public class Result : EntityObject, IDataObject ....

public class ResultDataManager : BaseDataManager<Result> ...

I want to implement service locator, which will return instance of IDataManager<T> for T

But I stucked how to implement it in a neat way without a lot of castings.

Any ideas?

UPDATE: I used to use the following code for discovering types for registring them with my previous service locator:

 foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
            {
                if (type.GetInterface("ISQLDataAccessManager") != null && !type.IsAbstract)
                {
                    var manager = (ISQLDataAccessManager)Activator.CreateInstance(type);

                    _managers.Add(type, manager);

                    var typeDO = manager.GetDataObjectType();

                    _typeNames2Types.Add(typeDO.FullName, typeDO);
                    _managers2BO.Add(typeDO, manager);
                }
            }

It seems that I don't really understand reflection with generics

+3  A: 

Here is a neat solution if having the locator as singleton is fine:

static class Locator
{
    private static class LocatorEntry<T> where T : ...
    {
        public static IDataManager<T> instance;
    }

    public static void Register<T>(IDataManager<T> instance) where T : ...
    {
        LocatorEntry<T>.instance = instance;
    }

    public static IDataManager<T> GetInstance<T>() where T : ...
    {
        return LocatorEntry<T>.instance;
    }
}

If you cannot implement the locator as singleton, I believe there is no there around creating a Dictionary<Type,object> and do some casts:

class Locator
{
    private readonly Dictionary<Type, object> instances;

    public Locator
    {
        this.instances = new Dictionary<Type, object>();
    }

    public void Register<T>(IDataManager<T> instance) where T : ...
    {
        this.instances[typeof(T)] = instance;
    }

    public IDataManager<T> GetInstance<T>() where T : ...
    {
        return (IDataManager<T>)this.instances[typeof(T)];
    }
}
dtb
I has your second snippet in mind but was concerning that something evades from my mind.So if I can't do any better than it without having singletons - that's the answer
vittore
However I will try to adopt your first snippet ...
vittore
@dtb: but for a first snippet how to discover all types inheriting from `IDataManager<T>` with reflection and register them?
vittore
The same way as you'd discover them using the second snippet. Discovery is a whole new problem. You may want to have a look at MEF. http://mef.codeplex.com/
dtb
@dtb: look how i used to discover them before in updated code
vittore
@dtb: MEF has limited support of generics as far as I remember btw
vittore
I don't think enumerating `Assembly.GetExecutingAssembly().GetTypes()` is a good idea. It smells IMO, but I may be wrong. I'd go with the second snippet and use your existing discovery code, or switch to a proper Dependency Injection framework or probably MEF.
dtb
@dtb: ok thank you any way, and i think first snippet is brilliant. The reason why I use reflection from current assembly is because I have more than hundred of T for which i have to register DataManagers
vittore
Also with MEF I also won't be able to export several generics and import them to one place... However with MEF it's possible not to use single service locator at all and import my datamanagers in places i need them. Have to think about it
vittore
@vittore: It's an interesting problem. Feel free to open a new question :) I'm not very familiar with MEF...
dtb
MEF is pretty awesome. Haven't used it with generics though.
dthorpe