2010-08-18 33 views
9

Tôi đang cố gắng tìm ra cách chính xác cách liên kết thứ gì đó như thế này với số thập phân.Sự phụ thuộc theo chu kỳ với ninject

interface IMainService 
{ 
    void DoStuff(); 
} 

interface IOtherService 
{ 
    void DoSomeMagic(); 
} 

abstract class BaseClass 
{ 
    //many stuff here 
} 

class MainClass : BaseClass, IMainService 
{ 
    public MainClass(IOtherService s) 
    { 
    } 

    public void DoStuff() 
    { 
     throw new NotImplementedException(); 
    } 

    //do many other things 
} 

class OtherClass : IOtherService 
{ 
    public OtherClass(IMainService s) 
    { 
    } 

    public void DoSomeMagic() 
    { 
     throw new NotImplementedException(); 
    } 
} 

class BaseModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<MainClass>().To<MainClass>(); 
     Bind<IMainService>().To<MainClass>(); 
     Bind<IOtherService>().To<OtherClass>(); 
    } 
} 

static class Program 
{ 
    static void Main() 
    { 
     var kernel = new StandardKernel(new BaseModule()); 
     var main = kernel.Get<MainClass>(); 
    } 
} 

Nó mang lại cho tôi ngoại lệ:

Error activating IOtherService using binding from IOtherService to OtherClass 
A cyclical dependency was detected between the constructors of two services. 

Activation path: 
    4) Injection of dependency IOtherService into parameter s of constructor of type MainClass 
    3) Injection of dependency IMainService into parameter s of constructor of type OtherClass 
    2) Injection of dependency IOtherService into parameter s of constructor of type MainClass 
    1) Request for MainClass 

Suggestions: 
    1) Ensure that you have not declared a dependency for IOtherService on any implementations of the service. 
    2) Consider combining the services into a single one to remove the cycle. 
    3) Use property injection instead of constructor injection, and implement IInitializable if you need initialization logic to be run after property values have been injected. 

Tôi không biết làm thế nào để viết BaseModule. Tôi chỉ cần một ví dụ của MainClass và một ví dụ của OtherClass (như singletons).

tôi đã cố gắng điều như thế:

Bind<MainClass>().To<MainClass>().InSingletonScope(); 
Bind<IMainService>().To<MainClass>().InRequestScope(); 
Bind<IOtherService>().To<OtherClass>().InSingletonScope(); 

Nhưng với cùng một lỗi.

Và cách viết ràng buộc để chỉ sử dụng một phiên bản cho giao diện MainClass và IMainService?

Cảm ơn câu trả lời.

Trả lời

15

Khi thông báo lỗi cho biết, bạn có một sự phụ thuộc theo chu kỳ giữa MainClassOtherClass vì bạn không thể tạo một đối tượng không có phiên bản kia. Lý tưởng nhất, bạn nên cấu trúc lại phân cấp lớp của bạn để loại bỏ yêu cầu này.

Nếu bạn không thể, giải pháp là sử dụng tính năng tiêm thuộc tính cho một (hoặc cả hai) lớp học, ví dụ:

public interface IMainService 
{ 
    void DoStuff(); 
    IOtherService OtherService { set; } 
} 

public class MainClass 
{ 
    public IOtherService OtherService { get; set; } 
    public void DoStuff() { ... } 
} 

public class OtherService 
{ 
    public OtherService(IMainService main) 
    { 
     main.OtherService = this; 
    } 
} 
+0

Cám ơn t tip của mình. Tôi tìm thấy giải pháp hoàn hảo với tiêm tài sản. Nhưng nó không có IOtherService OtherService {set; } trên IMainServices, bởi vì khi tôi trang trí tài sản với [Tiêm], Ninject thêm cá thể chính xác vào nó một mình. –

+4

Điều này không hoạt động. Với phiên bản mới nhất của Ninject, nó sẽ ném một 'StackOverflowException' nếu bạn sử dụng thuộc tính tiêm cho cả hai, và sẽ ném" phụ thuộc chu kỳ đã được phát hiện "nếu chỉ có một là sử dụng tiêm tài sản (và tiêm constructor khác). –

+4

Ah, nhưng nó * không * hoạt động miễn là bạn đang sử dụng phạm vi khác với phạm vi tạm thời (mặc định). –

2

Tôi nghĩ bạn không nên sử dụng các thuộc tính hoặc phương pháp setter cho điều này, bạn nên sử dụng Lazyness. Khái niệm về sự lười biếng giải quyết vấn đề. Vấn đề là nếu bạn có sự phụ thuộc vòng tròn giữa các đối tượng, nó trở thành không rõ ràng những gì để tạo ra một đầu tiên. Lười biếng giải quyết là: một khi một đối tượng thực sự được sử dụng (nói chung là trường hợp này khi một phương pháp công cộng được gọi là, nó cần phải tồn tại). Xin vui lòng tránh các tài sản hoặc người định cư nếu bạn có thể có thể. Chúng làm cho đối tượng của bạn có thể thay đổi (xấu đối với an toàn luồng và không cần thiết khi phụ thuộc chỉ được tiêm một lần).

Bạn constructors sẽ trông như thế này:

public OtherService(Lazy<IMainService> main) 
{ 
    this.main = main; 
} 

public MainClass(Lazy<IOtherService> s) 
{ 
    this.s = s; 
} 

Bạn có thể mô tả những phụ thuộc lười biếng trong bạn mô-đun Ninject bằng cách sử dụng phương thức Load bằng cách gọi "ToMethod (" phương pháp lambda tạo ra phương pháp Lazy dựa trên phương pháp get ").

một ví dụ rõ ràng về cách lazyness có thể giải quyết phụ thuộc vòng tròn với Ninject được trình bày ở đây. Nó cũng mô tả một phương pháp helper (BindLazy) để giải quyết vấn đề của bạn. https://www.codeproject.com/Tips/1171940/How-Ninject-Can-Help-in-Resolving-Circular-Depende

+0

Tôi đã sử dụng cái này. Điều này khá gọn gàng! –

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