So I thought I'd be slick and try this. I need to pass around a context without newing it up every time AND be able to define the mappings (Entity framework) -- in order to do this I need to inherit then override the DbContext class. I'd like to keep it plugable with any context I toss in so that's what led me to this. I got a IRepository interface that takes a (entity) with your usual suspects in it, and an implementation of it with a dependency on IContextFactory ...
public interface IContextFactory<T> where T : DbContext
{
T Context { get; }
}
And on my "EFRepository"
public class EFRepository<T, TContext> : IRepository<T> where T : class
where TContext : DbContext
{
public EFRepository(IContextFactory<TContext> contextFactory)
{
}
}
In my mapping, I did one of these jobs ...
x.For(typeof(IContextFactory<>)).Use(typeof(ContextFactory<>));
x.For(typeof(IRepository<>)).Use(typeof(EFRepository<,>));
Ok cool. In my unit tests, I try it this way...
var repository = ObjectFactory.GetInstance<EFRepository<Currency, EFContext>>();
var repository2 = ObjectFactory.GetInstance<IRepository<Currency>>();
First one works, no problem. 2nd one, I get hit with
The number of generic arguments provided doesn't equal the arity of the generic type definitio开发者_如何学Cn. Parameter name: instantiation
I'm guessing it's because I'm not telling structuremap which generic to pass on to IRepository since I'm passing 2? How do I do that? ...can I do that?
This should be possible but it's really messy... unless someone knows of a better way.
First you need to change how you create EFRepository<,>
. Using the .Use(context => ...)
overload you can access the context like context.BuildStack.Current.RequestedType.GetGenericArguments()
to get the generic type you want to access. Then you can new up new instance of EFRepository<,>
using reflection and getting the IContextFactory
from the context.
So regardless, something like
ObjectFactory.Configure(x =>
{
x.For(typeof(IContextFactory<>)).Use(typeof(ContextFactory<>));
x.For(typeof (IRepository<>)).Use(context =>
{
Type arg1 = context.BuildStack.Current.RequestedType.
GetGenericArguments()[0];
Type targetType =
typeof (EfRepository<,>).MakeGenericType(new[] {arg1, typeof (IContextFactory<>)});
return Activator.CreateInstance(targetType,
new[] {context.GetInstance(typeof (IContextFactory<>))});
});
//x.For(typeof(IRepository<>)).Use(typeof(EfRepository<,>));
});
var repository = ObjectFactory.GetInstance<EfRepository<Currency, EfContext>>();
var repository2 = ObjectFactory.GetInstance<IRepository<Currency>>();
Will get you most of the way there. I think you still need to properly set the generic for the second generic parameter of targetType before it will work though.
精彩评论