2012-02-14 63 views
5

Tôi đang thử dùng Ninject và tôi đang sửa đổi mã tôi đã viết với Sơ đồ cấu trúc để xem nó dễ dàng như thế nào. Trong mã cơ sở này, tôi có một đồ thị các đối tượng có cấu hình khác nhau thông qua các cơ quan đăng ký Bản đồ Cấu trúc và một đối tượng được sử dụng khi được chạy thông qua một giá trị trong cơ sở dữ liệu (trong trường hợp này để lấy lại một cơ quan dịch vụ wcf với một số đối tượng được tiêm) . Ví dụ: (sử dụng mã Bản đồ Cấu trúc):Sử dụng tên để phân biệt đối tượng bằng cách sử dụng IoC

Registry 1 thiết lập tất cả các giá trị mặc định cho các loại IBusinessContext, IRules và ILogger. Điều này chỉ là thêm các kiểu GenericContext/Logger/Rules bên cạnh các giao diện mà không có chuyên môn nào khác.

public GenericRegistry() 
    { 
     // Set up some generic bindings here 
     For<ILogger>().Use<Loggers.GenericLogger>(); 
     For<IBusinessRule>().Use<Rules.StandardRule>(); 
     For<IBusinessContext>().Use<Contexts.GenericBusinessContext>(); 
     For<ILoggerContext>().Use<Loggers.GenericLoggerContext>(); 
    } 

Đăng ký 2 thiết lập IBusinessTiếp theo để sử dụng lớp SpecialisedContext và yêu cầu người quản lý sử dụng SpecializedLogger. Ví dụ cho IBusinessContext được đặt tên là "SpecializedContext".

public SpecializedRegistry() 
    { 
     // Old style syntax as it affects the default for IBusinessContext 
     // Perhaps a hint at what I'm doing? 
     InstanceOf<IBusinessContext>().Is.OfConcreteType<Contexts.SpecializedBusinessContext>().Named(SpecializedInstanceName).Ctor<ILogger>().Is<Loggers.SpecialisedLogger>(); 
    } 

Tất cả đều hoạt động như mong đợi trong Bản đồ cấu trúc (tùy thuộc vào cú pháp cũ hoặc mới).

Tuy nhiên, khi tôi đã sử dụng Ninject tôi nhấn một vấn đề với hy vọng trường hợp chưa đặt tên là mặc định (không phải cách Ninject hoạt động, tôi nhận được điều đó). Điều này dẫn đến một số nghiên cứu mà tất cả đều gợi ý rằng việc sử dụng các cá thể có tên là A Really Bad Idea. Tôi hiểu rằng có nhiều cách tốt hơn để thực hiện việc này bằng cách sử dụng đăng ký tự động hoặc thuộc tính để đặt tên hoặc yêu cầu một loại nhất định, nhưng trong hệ thống tôi mô tả cần phải có cách để chạy ở trên cùng của cây (và để cho khuôn khổ IoC tìm ra phần còn lại dựa trên các loại hoặc quy tắc đã đăng ký).

Vì vậy ... tôi chỉ sử dụng khái niệm IoC sai ở đây bằng cách mong đợi để yêu cầu đối tượng cấp cao nhất của tôi theo tên hoặc có cách nào tốt hơn để làm những gì tôi đang cố gắng làm? Tôi có nên sử dụng một cái gì đó như MEF thay vào đó và xử lý tất cả điều này giống như plug-in?

Tôi nhấn mạnh Tôi không sử dụng điều này giống như một nhà máy câm và yêu cầu ở mỗi cấp mã cho một thể hiện loại x từ container, nó chỉ là hành động khởi tạo.

Cảm ơn trước cho thời gian của bạn và giúp :)

Trả lời

3

Không có gì tất cả những gì sai với việc thiết lập các ràng buộc Ninject theo tên, nếu đó là cách duy nhất để đạt được những gì nó là bạn cần IMO là.

Vì vậy, các cú pháp cơ bản là:

Bind<IBusinessContext>().To<ConcreteBusinessContext>().Named("XYZ"); 

Hoặc nếu bạn cần một lớp gọi điện thoại cụ thể để có được một ràng buộc khác nhau thì bạn có thể thử:

Bind<IIBusinessContext>().To<SomeOtherConcreteBusinessContext>().WhenInjectedInto<TypeOfCallingClass>(); 

Tuy nhiên, nếu lớp gọi (I đang nói về lớp có IBusinessContext trong ctor của nó) cung cấp giá trị cấu hình xác định loại bê tông cần tải, sau đó bạn sẽ cần phải sử dụng một đại biểu:

Bind<Func<string, IBusinessContext>>().ToMethod(ctx => str => DetermineWhichConcreteTypeToLoad(ctx, str)); 

//messy sudo code 
static DetermineWhichConcreteTypeToLoad(IContext ctx, string str) 
{ 
    if(str == "somevalue"){ 
     return ctx.Kernel.Get<ConcreteType1>(); 
    else 
     return ctx.Kernel.Get<ConcreteType2>(); 
} 

và lớp gọi điện thoại của bạn sẽ giống như thế:

class DoStuff 
{ 
    Func<string, IBusinessContext>> contextFunc; 

    DoStuff(Func<string, IBusinessContext>> contextFunc) 
    { 
     this.contextFunc = contextFunc; 
    } 

    void SomeMethod() 
    { 
     var configuredValue = GetConfiguredValueSomehow(); 
     var context = contextFunc(configuredValue); //<-- this passes your config value back to ninject in the ToMethod() lambda 
     //do something with context 
    } 
} 

Trong ví dụ rằng không có nhu cầu về các trường hợp được đặt tên, như bạn có một phương pháp mà tải các loại bê tông đặc biệt, tuy nhiên bạn vẫn có thể sử dụng các trường hợp đặt tên nếu bạn muốn làm một cái gì đó như thế này:

Bind<IBusinessContext>().To<ConcreteBusinessContext>().Named("config1"); 
Bind<IBusinessContext>().To<SomeOtherBusinessContext>().Named("config2"); 

Bind<Func<string, IBusinessContext>>().ToMethod(ctx => str => ctx.Kernel.Get<IBusinessContext>().Named(str)); 

class DoStuff 
{ 
    Func<string, IBusinessContext>> contextFunc; 

    DoStuff(Func<string, IBusinessContext>> contextFunc) 
    { 
     this.contextFunc = contextFunc; 
    } 

    void SomeMethod() 
    { 
     var configuredValue = "config1"; 
     var context = contextFunc(configuredValue); //<-- this will passthrough "config1" to the above ToMethod() method and ask for a IBusinessContext named "config1" 

    } 
} 

EDIT: Tôi quên đề cập đến nếu giá trị cấu hình của bạn không phải đến từ mã gọi, điều này sẽ giúp mọi thứ dễ dàng hơn nhiều. Mã của bạn thay vì có thể giống như thế:

// this method can just be a global method in you app somewhere 
static string GetConfigValue() 
{ 
    //something like 
    return AppSetting.Get("config"); 
} 

Bind<IBusinessContext>().To<ConcreteBusinessContext>().When(r => GetConfigValue() == "config1"); 
Bind<IBusinessContext>().To<SomeOtherBusinessContext>().When(r => GetConfigValue() == "config2"); 

class DoStuff 
{ 
    IBusinessContext context; 

    DoStuff(BusinessContext context) 
    { 
     this.context = context; 
    } 

    void SomeMethod() 
    { 
     //use the context value as you normally would 
    } 
} 

Bạn có thể sáng tạo và thay vì sử dụng dây ma thuật, phương pháp cấu hình của bạn có thể tải lên một enum và phương pháp Khi() của bạn có thể kiểm tra cho sự bình đẳng đối với một enum thay vì một chuỗi, nhưng bạn có được ý tưởng. Điều này được gọi là ràng buộc theo ngữ cảnh trong ninject, và tôi có thể nói với bạn như một người sử dụng avid một lần của SM, điều này là mạnh hơn rất nhiều so với bất cứ điều gì SM có. Kiểm tra phần còn lại của phương thức When() và xem bạn có thể làm gì.

+0

Cảm ơn Aaron! Đó là xóa một vài điều cho tôi :) Nó rất đánh giá cao. – NoodleAwa

Các vấn đề liên quan