简体   繁体   中英

implement repository factory C#

I have a website that is using the following code to return a repository, it will accept an interface and return the firt implementation it finds, however, I think the code is too slow and causing issues, is there any better ways to implement this?

Thanks

 public T For<T>() where T : class
    {
        T returnVar = null;
        Assembly asm = Assembly.GetExecutingAssembly();

        var types = asm.GetTypes().Where(x => x.IsClass == true && x.Namespace != null && x.Namespace.StartsWith("Website.Core.Data.Repositories"));

        var result = types.Where(x => x.GetInterface(typeof(T).Name) != null);

        foreach (var x in result)
        {    
            var mi = x.GetConstructors();
            returnVar = (T)asm.CreateInstance(x.UnderlyingSystemType.ToString());
        }

        if (returnVar != null)
            return returnVar;
        else
            throw new Exception("No Repository for: " + typeof(T).Name);        
    }

An obvious optimization would be to cache the result of each type T (if you want new instances each time, then cache the type and constructor info).

The result of locating the correct type by looking in the assembly is not going to change at runtime.

On another note you might be better off using an IoC container for this.

Why didn't you try to use a DI container instead? Something like Autofac should be fairly easy to put in even without knowledge and pretty fast in terms of runtime excution (obvious alternatives are Windsor and maybe StructureMap. Heard stuff about Ninject performance but it was long time ago, not sure about Microsoft Unity but likely not one of the best for speed).

Read the code on this page. You'll like it :)
http://code.google.com/p/autofac/wiki/Scanning

How about this:

private readonly Dictionary<Type, object> _items = new Dictionary<Type, object>();

    public T For<T>() where T : class
    {
        Type serviceType = typeof (T);
        lock (_items)
        {
            object instance;
            if (_items.TryGetValue(serviceType, out instance))
                return (T) instance;
        }


        Assembly asm = Assembly.GetExecutingAssembly();
        var types = asm.GetTypes().Where(x => x.IsClass
                                              && !x.IsAbstract
                                              && serviceType.IsAssignableFrom(x)
            );

        T returnVar = null;
        foreach (Type x in types)
        {
            ConstructorInfo[] mi = x.GetConstructors();
            returnVar = (T) asm.CreateInstance(x.UnderlyingSystemType.ToString());
        }

        if (returnVar != null)
        {
            lock (_items)
                _items.Add(serviceType, returnVar);
            return returnVar;
        }
        throw new Exception("No Repository for: " + typeof (T).Name);
    }

I think what your building here is sort of a makeshift IOC container. The trick is saving the mapping between the interface and the class after you first resolve it so that you dont have to look it up every time. So this class will need state to improve performance.

But i might consider reading up on IOC and using a fully functional IOC container such as Windsor Castle or Unity to resolve these mappings. I believe Windor Castle will by default resolve your interfaces that have an I in front of them to classes without it (IOrderProcessor -> OrderProcessor).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM