Registering Method on Generic Factory with StructureMap

被刻印的时光 ゝ 提交于 2020-01-03 17:20:49

问题


I am trying to use a method on a generic factory class in my structuremap registry. Normally, i would use the following when registering a type using a factory method:

For<Foo>().Use(x => new FooFactory().GetFoo());

And the following when registering a generic type:

For(typeof(ISomeGeneric<>)).Use(typeof(SomeGeneric<>));

How can I combine the two and retrieve a generic type from a generic factory method? I think it should be something like:

For(typeof(IFoo<>)).Use(typeof(x => new FooFactory<>().Create(someParameter));

This just gives a

"Cannot convert lambda expression to type object because it is not a delegate type" 

error. I've tried various combinations but am stumped. Any ideas?

Thanks.


回答1:


This is possible, BUT I would look for an alternative if you can. The issue is that to work with the open generic, you have to use some reflection. This means you will take a performance hit.

public class FooRegistry:Registry
{
    public FooRegistry()
    {
        For(typeof(IFoo<>)).Use(x =>
        {
            var ParamType = x.BuildStack.Current.RequestedType
                             .GetGenericArguments()[0];
            return BuildUsingFooFactory(ParamType);
        });
    }

    private object BuildUsingFooFactory(Type paramType)
    {
        var factoryType = typeof (FooFactory<>).MakeGenericType(new[] {paramType});
        var createMethod = factoryType.GetMethod("Create");
        object factory = Activator.CreateInstance(factoryType);
        return createMethod.Invoke(factory, new[] {"SomeParameterString"});
    }
}

public class FooFactory<T>
{
    public IFoo<T> Create(string param)
    {
        return new Foo<T>();
    }

}

public interface IFoo<T>
{
}

public class Foo<T> : IFoo<T>
{   
}

What you are doing in order is the following:

  1. Find out what the requested generic argument is. (ParamType)
  2. Create a non-open generic type for the factory (factoryType)
  3. Grab the create method off of it. (createMethod)
  4. Create an instance of the factory using the Activator (factory)
  5. Call the create method on the factory instance with your some parameter.

StructureMap takes care of casting the output to the right interface.

Better Solution

Instead of using the IFoo directly, use the IFooFactory. This makes it much cleaner, you have an open generic mapping to the IFooFactory<>. Then just get the type of FooFactory you need to generate your objects.

public class FooRegistry:Registry
{
    public FooRegistry()
    {
        For(typeof (IFooFactory<>))
            .Use(typeof (FooFactory<>))
            .CtorDependency<string>("connection")
            .Is("SomeConnectionString");
    }
}


public interface IFooFactory<T>
{
    IFoo<T> CreateInstance();
}

public class FooFactory<T> : IFooFactory<T>
{
    public FooFactory(string connection)
    {
    } 

    public IFoo<T> CreateInstance()
    {
        return new Foo<T>();
    }
}

public interface IFoo<T>
{
}

public class Foo<T> : IFoo<T>
{   
}


来源:https://stackoverflow.com/questions/10671078/registering-method-on-generic-factory-with-structuremap

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!