Register a method for a shared Factory with StructureMap

I am trying to use a method in a common factory class in my system registry. Typically, when registering a type using the factory method, I would use the following:

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

And when registering a generic type:

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

How can I combine these two and get 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)); 

It just gives

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

error. I tried different combinations, but I'm at a dead end. Any ideas?

Thanks.

+4
source share
1 answer

It is possible, BUT I would look for an alternative, if possible. The problem is that to work with an open generic, you must use some reflection. This means that you get 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 do in order is the following:

  • Find out what the requested general argument is. (ParamType)
  • Create a non-open generic type for factory (factoryType)
  • Remove the creation method from it. (CreateMethod)
  • Create a factory instance using an activator (factory)
  • Call the create method on the factory instance with your some parameter.

StructureMap takes care of outputting output to the right interface.

The best decision

Instead of using IFoo directly, use IFooFactory. This makes it a lot cleaner, you have an open shared mapping with IFooFactory <>. Then just get the type of FooFactory that you need to create 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> { } 
0
source

Source: https://habr.com/ru/post/1413372/


All Articles