2012-10-08 66 views
3

是否有可能建立一个ninject绑定来尊重泛型约束?Ninject - 约束绑定泛型类型

例如:

interface IFoo { } 
interface IBar { } 
interface IRepository<T> { } 

class FooRepository<T> : IRepository<T> where T : IFoo { } 
class BarRepository<T> : IRepository<T> where T : IBar { } 

class Foo : IFoo { } 
class Bar : IBar { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     IKernel kernel = new StandardKernel(); 

     // Use this binding only where T : IFoo 
     kernel.Bind(typeof(IRepository<>)).To(typeof(FooRepository<>)); 

     // Use this one only where T : IBar 
     kernel.Bind(typeof(IRepository<>)).To(typeof(BarRepository<>)); 

     var fooRepository = kernel.Get<IRepository<Foo>>(); 
     var barRepository = kernel.Get<IRepository<Bar>>(); 
    } 
} 

调用此代码原样会产生多个激活路径异常: -

错误激活IRepository {富}:一个以上的匹配绑定可用。

如何设置绑定条件的T值?理想情况下,我希望他们从目标类型中挑选约束,因为我已经在那里定义了它们,但是如果我必须在绑定中再次定义它们,那也是可以接受的。

+0

@Stephen:我不认为调用堆栈是真的有必要。它使问题产生误导,因为问题不是我为IRepository <>定义了两个绑定,而是我想让它们都以T的值为条件,根据注释尊重目标类型上的泛型类型约束在我的代码中。 –

+0

这是你的问题,所以随时删除堆栈跟踪;-)。但是,由于我的印象是您的注册会起作用,所以我认为很好的证明它没有。也许我同意你的看法,只是错误信息就足够了。不幸的是,Ninject似乎并不支持这种情况(开箱即用),而其他框架,如Autofac和Simple Injector确实支持这种情况。 – Steven

+0

很酷,我已经编辑过并且留下了错误信息。正如你所说,可能更重要的是要更清楚地表明它*不*按原样工作。你说这在Autofac中可以直接使用?也许这就是我的解决方案,然后... –

回答

1

也许有一个更清洁的解决方案,但它肯定与Whencontextual binding方法和一些反思工作:

// Use this binding only where T : IFoo 
kernel.Bind(typeof(IRepository<>)).To(typeof(FooRepository<>)) 
    .When(r => typeof(IFoo).IsAssignableFrom(r.Service.GetGenericArguments()[0])); 

// Use this one only where T : IBar 
kernel.Bind(typeof(IRepository<>)).To(typeof(BarRepository<>)) 
    .When(r => typeof(IBar).IsAssignableFrom(r.Service.GetGenericArguments()[0])); 
+0

圣可丽饼,这是一些讨厌的,讨厌的代码!最糟糕的是,每次在解决“IRepopository ”时都会调用每个lambda。 – Steven

+0

我打算接受这个答案,但要记住大型项目(IFoo和IBar是更大组接口的一部分),使用反射并为每个类型设置单独的绑定可能更为谨慎。 –