2009-04-13 30 views
29

Ai đó có thể giải thích tiêm phụ thuộcvớimột ví dụ cơ bản .NET và cung cấp một vài liên kết tới tài nguyên .NET để mở rộng đối tượng?Dependency Injection in .NET với các ví dụ?

Đây không phải là bản sao của What is dependency injection? vì tôi hỏi về các ví dụ và tài nguyên .NET cụ thể.

+1

Martin Fowler có mô tả bao gồm: http: // martinfowler. com/articles/injection.html Theo như tài nguyên .NET, hãy xem: - [Castle Windsor] (http://www.castleproject.org/container/index.html) - [Spring.NET] (http: //www.springframework.net/) - [Autofac] (http://code.google.com/p/autofac/) - [Ninject] (http://ninject.org/) - [Unity] (http: //www.codeplex.com/unity) - [Sơ đồ cấu trúc] (http://structuremap.sourceforge.net/) – Codebrain

+0

Hãy xem các bài viết sau đây có thể cung cấp một số trợ giúp về điều này: * [Windsor IoC Container trên một Nghỉ trưa] (http://jeremyjarrell.com/archive/2007/07/12/44.aspx) * [Bài viết MSDN về Inversion kiểm soát và Dependency Injection] (http://msdn.microsoft.com/en-us/library/aa973811.aspx) Liên kết chung về vùng chứa: * [Castle Project] (http: // www .castleproject.org/container/index.html) Vài liên kết SO có thể giúp thêm những điều về chủ đề: * [Câu hỏi Castle Windsor] (http://stackoverflow.com/questions/tagged/castle-windsor) * [ Câu hỏi IoC] (http://stackoverflow.com/questions/t –

Trả lời

32

Đây là một ví dụ phổ biến. Bạn cần phải đăng nhập vào ứng dụng của bạn. Tuy nhiên, tại thời điểm thiết kế, bạn không chắc chắn nếu khách hàng muốn đăng nhập vào cơ sở dữ liệu, tệp hoặc nhật ký sự kiện.

Vì vậy, bạn muốn sử dụng DI để trì hoãn lựa chọn đó thành lựa chọn có thể được khách hàng định cấu hình.

Đây là một số giả (khoảng dựa trên Unity):

Bạn tạo một giao diện đăng nhập:

public interface ILog 
{ 
    void Log(string text); 
} 

sau đó sử dụng giao diện này trong lớp học của bạn

public class SomeClass 
{ 
    [Dependency] 
    public ILog Log {get;set;} 
} 

tiêm những người phụ thuộc vào thời gian chạy

public class SomeClassFactory 
{ 
    public SomeClass Create() 
    { 
    var result = new SomeClass(); 
    DependencyInjector.Inject(result); 
    return result; 
    } 
} 

và các trường hợp được cấu hình trong app.config:

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <configSections> 
    <section name ="unity" 
      type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, 
       Microsoft.Practices.Unity.Configuration"/> 
    </configSections> 
    <unity> 
    <typeAliases> 
     <typeAlias alias="singleton" 
       type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,Microsoft.Practices.Unity" /> 
    </typeAliases> 
    <containers> 
     <container> 
     <types> 
      <type type="MyAssembly.ILog,MyAssembly" 
       mapTo="MyImplementations.SqlLog, MyImplementations"> 
      <lifetime type="singleton"/> 
      </type> 
     </types> 
     </container> 
    </containers> 
    </unity> 
</configuration> 

Bây giờ nếu bạn muốn thay đổi kiểu logger, bạn chỉ cần đi vào cấu hình và xác định loại khác.

+48

Đó không phải là vấn đề. – Will

+2

nó không thực sự :) - cảm ơn cho ví dụ hữu ích – JohnIdol

+1

Tại sao chúng tôi không thể sử dụng một số thuộc tính tùy chỉnh và xác định 1 = cơ sở dữ liệu, 2 = tệp và v.v ...? Những gì chúng ta cần Unity? –

0

Bạn về cơ bản truyền vào tất cả các đối tượng cần thiết trong hàm tạo. Ngoài ra, bạn có thể giải quyết chúng trong thời gian chạy bằng cách sử dụng một trình phân giải giao diện (mặc dù điều này kém an toàn hơn). Bạn có thể tìm thấy các ví dụ tuyệt vời tại trang web Ninject cho phương pháp tiếp cận đầu tiên và các ví dụ hay tại trang web Unity cho phương pháp thứ hai. Điều này tránh sự cần thiết cho người độc thân và cho phép bạn dễ dàng thả một vật thể thay thế phù hợp với giao diện mong muốn

1

Tôi đã có Dependency Injection với một ví dụ thực sự đơn giản như thế này.

Xem lớp bên dưới, bạn sẽ nhận được toàn bộ ý tưởng. Như bạn thấy, trừ khi bạn cung cấp tệp, tệp này sẽ sử dụng tệp cài đặt mặc định, nhưng bạn có thể đặt tệp cài đặt và sau đó lớp sẽ sử dụng tệp đó.

Public Class ProcessFile 

Private _SettingsFile As String = "settings.bin" 

Public Sub New() 
End Sub 

Public Sub New(settings As String) 
_SettingsFile= settings 
End Sub 

Public Function ReadFile() As String 
'Do stuff based on the settings stored in the _SettingsFile 
End Function 

End Class 

Rõ ràng đây là trường hợp cơ bản nhất. Trong thế giới thực, bạn có thể làm điều tương tự với các loại lớp, chẳng hạn như bạn đã có Lớp cơ sở dữ liệu và bạn có thể chuyển dll cơ sở dữ liệu bên dưới bằng cách thực hiện tiêm phụ thuộc và mã của bạn sẽ hoạt động với bất kỳ cơ sở dữ liệu nào ngay khi bạn có thể cung cấp lớp hợp lệ (một lớp thực hiện giao diện bạn đang sử dụng).

Sau khi có cơ bản, bạn có thể làm điều này trên phạm vi rộng hơn và hoàn toàn độc lập khỏi ứng dụng bằng cách sử dụng các khuôn khổ DI như sự hiệp nhất.

30

Ninject phải có một trong những mẫu tuyệt vời ngoài kia: (chắp từ mẫu)

interface IWeapon { 
    void Hit(string target); 
} 
class Sword : IWeapon { 
    public void Hit(string target) { 
    Console.WriteLine("Chopped {0} clean in half", target); 
    } 
} 
class Shuriken : IWeapon { 
    public void Hit(string target) { 
    Console.WriteLine("Shuriken tossed on {0}", target); 
    } 
} 
class Samurai { 
    private IWeapon _weapon; 

    [Inject] 
    public Samurai(IWeapon weapon) { 
    _weapon = weapon; 
    } 

    public void Attack(string target) { 
    _weapon.Hit(target); 
    } 
} 

class WeaponsModule: NinjectModule { 
    private readonly bool _useMeleeWeapons; 

    public WeaponsModule(bool useMeleeWeapons) { 
    _useMeleeWeapons = useMeleeWeapons; 
    } 

    public void Load() { 
    if (useMeleeWeapons) 
     Bind<IWeapon>().To<Sword>(); 
    else 
     Bind<IWeapon>().To<Shuriken>(); 
    } 
} 

class Program { 
    public static void Main() { 
    bool useMeleeWeapons = false; 
    IKernel kernel = new StandardKernel(new WeaponsModule(useMeleeWeapons)); 
    Samurai warrior = kernel.Get<Samurai>(); 
    warrior.Attack("the evildoers"); 
    } 
} 

này, với tôi, đọc rất trôi chảy, trước khi bạn bắt đầu lên võ đường của bạn, bạn có thể quyết định làm thế nào để cánh tay của bạn Samurais.

+2

Tôi xin lỗi, tôi không hiểu. Tại sao điều này tốt hơn tôi viết mã mà "Samurai mới (useMeleeWeapons);"? Đây có phải là thông thạo nhất không? – Nabheet

+1

Giả sử bạn có một đội quân 10.000 samurais ... và bạn viết dòng đó 10.000 lần ... và sau đó bạn muốn thay đổi nó, nhưng than ôi, bạn không thể sử dụng công cụ tìm/thay thế của trình soạn thảo ... ở trên Ví dụ, tất cả những gì bạn cần làm là thay đổi 'WeaponsModule' :) – Noctis

+2

Khi nào và như thế nào' Load() 'được gọi trong' WeaponsModule'? – GFoley83

0

Cài đặt bên dưới gói Nuget trong tên dự án mvc4 chính SampleDependency. Unity.mvc4, unity.webapi và MicrosoftAsp.Net Web API chủ 2.2 Web

Trong dự án web

public static class Bootstrapper 
{ 
    public static IUnityContainer Initialise() 
    { 
     var container = BuildUnityContainer(); 

     DependencyResolver.SetResolver(new UnityDependencyResolver(container)); 
     GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container); 

     return container; 
    } 

    private static IUnityContainer BuildUnityContainer() 
    { 
     var container = new UnityContainer(); 

     // register all your components with the container here 
     // it is NOT necessary to register your controllers 

     // e.g. container.RegisterType<ITestService, TestService>(); 
     container.RegisterType<IUserDetailLogic, UserDetailLogic>(); 
     container.RegisterType<IUserData, UserData>(); 

     RegisterTypes(container); 

     return container; 
    } 
    public static void RegisterTypes(IUnityContainer container) 
    { 

    } 
} 
0

Tạo dự án lớp DB (thư viện lớp) và thêm bên dưới mã trong nó.

public class UserData : IUserData 
{ 
    public string getUserDetails() 
    { 
     return "Asif"; 
    } 
} 

public interface IUserData 
{ 
    string getUserDetails(); 
} 
0

Thêm dự án logic kinh doanh của thư viện lớp loại và thêm mã bên dưới vào trong đó. lớp công khai UserDetailLogic: IUserDetailLogic { riêng IUserData _userData = null;

public UserDetailLogic(IUserData userData) 
    { 
     _userData = userData; 
    } 
    public string getUserDetails() 
    { 
     return _userData.getUserDetails(); 
    } 
} 

public interface IUserDetailLogic 
{ 
    string getUserDetails(); 
} 

Trong dự án chính, bạn thêm mã bên dưới vào bộ điều khiển nhà.

lớp công khai HomeController: Bộ điều khiển { riêng tư chỉ đọc IUserDetailLogic _userDetailLogic;

public HomeController(IUserDetailLogic userDetailLogic) 
    { 
     _userDetailLogic = userDetailLogic; 
    } 

    public ActionResult Index() 
    { 
     ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; 
     string str = _userDetailLogic.getUserDetails(); 
     return View(); 
    } 

    public ActionResult About() 
    { 
     ViewBag.Message = "Your app description page."; 

     return View(); 
    } 

    public ActionResult Contact() 
    { 
     ViewBag.Message = "Your contact page."; 

     return View(); 
    } 
} 
+0

Bài đăng hay nhưng nó có một chút không rõ ràng (đối với tôi ít nhất) khi tôi nhận thấy userData sử dụng giao diện IUserData (Thay vì IUserDetailLogic có thể?). Ngoài ra HomeController hy vọng IUserDetailLogic userDetailLogic, trong kinh nghiệm/kiến ​​thức của tôi, không biết nó sẽ đến từ đâu. – Ichirichi

3

Tôi nghĩ điều quan trọng là bạn phải học DI trước khi không có IoC Containers. Vì vậy, tôi đã viết một ví dụ mà từ từ builts lên đến một container IoC. Đó là một ví dụ thực sự từ công việc của tôi, nhưng vẫn làm đủ cơ bản cho người mới để lấy bản chất của DI. Bạn có thể tìm thấy nó ở đây: https://dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/

Đó là trong C# .NET và sau này sử dụng Unity.

Cập nhật sau khi bình luận:

phần có liên quan của bài viết

"Hãy quan sát những thay đổi sau đây để thiết kế ban đầu:

quick graph of situation

Chúng tôi đã đi cho“Constructor tiêm ”Mẫu để triển khai DI và các bước tái cấu trúc là:

  1. Tóm tắt giao diện của CardPresenceChecker bằng cách tạo Giao diện ICardPresenceChecker;
  2. Làm rõ rằng CardPresenceChecker này chỉ hoạt động đối với thư viện của Công ty X, bằng cách đổi tên thành XCardPresenceChecker;
  3. XCardPresenceChecker triển khai Giao diện ICardPresenceChecker;
  4. Tóm tắt thuộc tính của LogInService là loại ICardPresenceChecker thay vì ‘biết’ chính xác việc triển khai được thực hiện trên tàu;
  5. Và cuối cùng nhưng không kém phần quan trọng, nhu cầu từ người dùng (nhà phát triển khác) của LogInService rằng họ cung cấp bất kỳ lớp nào ít nhất là triển khai ICardPresenceChecker để LogInService có thể thực hiện điều đó.

constructor LogInService của trông giống như:

this.myCardPresenceChecker = cardPresenceChecker; 
this.myCardPresenceChecker.CardIn += MyCardPresenceChecker_CardIn; 
this.myCardPresenceChecker.CardOut += MyCardPresenceChecker_CardOut; 
this.myCardPresenceChecker.Init(); 

Vì vậy, nơi nào mà bạn cung cấp LogInService với một thực hiện ICardPresenceChecker? Bạn thường muốn "ánh xạ" này (trong ví dụ này, chúng tôi sẽ "ánh xạ" ICardPresenceChecker tới XCardPresenceChecker) tại một vị trí trung tâm khi khởi động ứng dụng, được biết đến khái niệm là "Gốc thành phần". Đối với Ứng dụng bảng điều khiển thông thường của một OL có thể là khoảng trống chính trong lớp Chương trình. Vì vậy, trong ví dụ này, đoạn mã này sẽ được sử dụng tại nơi aformentioned:

LogInService logInService = LogInService mới (XCardPresenceChecker mới());"

+1

Trong khi liên kết này có thể trả lời câu hỏi, tốt hơn nên bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở thành không hợp lệ nếu trang được liên kết thay đổi. - [Từ đánh giá] (/ review/low-quality-posts/11421227) –

+0

@Nahuel lanni: Trong khi tôi đánh giá cao nhận xét của bạn và tôi sẽ cố gắng tuân thủ, quan điểm của tôi thực sự quan trọng là đọc toàn bộ bài viết và không chỉ cố gắng học hỏi từ một số đoạn mã ngẫu nhiên. Nhưng ... Xem câu trả lời đã sửa đổi. Hi vọng điêu nay co ich. –

+0

IoC? Đó là gì? :-( – Ichirichi

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