2009-02-05 29 views
22

Tôi đang làm việc trên một dự án mà khuôn khổ Unity được sử dụng như là container IoC. Câu hỏi của tôi liên quan đến việc tiêm một phụ thuộc tùy chọn (trong trường hợp này là một logger) vào một số lớp bằng cách sử dụng tiêm thuộc tính hoặc setter.Setter/thuộc tính tiêm trong Unity mà không có thuộc tính

Tôi không muốn làm lộn xộn các nhà xây dựng của tất cả các lớp học với các phụ thuộc tùy chọn này, nhưng tôi không thể tìm ra cách tốt để xử lý điều này trong Unity. Cách bạn sẽ làm điều này là, theo MSDN documentation, bằng cách thêm một thuộc tính đối với tài sản:

private ILogger logger; 

[Dependency] 
public ILogger Logger 
{ 
get { return logger; } 
    set { logger = value; } 
} 

Tôi tìm thấy điều này rất xấu xí. Trong StructureMap, người ta có thể làm như sau để đặt tất cả các thuộc tính của một loại nhất định:

SetAllProperties(policy => policy.OfType<ILog>()); 

Có ai biết nếu có thể làm điều gì đó tương tự trong Unity không?

Edit:

Kim Major gợi ý sử dụng this approach mà cũng có thể đạt được thông qua mã.

Tôi sẽ quan tâm đến các ví dụ về cách thực hiện điều này tự động cho tất cả các thuộc tính phù hợp.

Trả lời

3

Hướng dẫn sau đây cho thấy một cách để thực hiện điều đó thông qua cấu hình. Tất nhiên bạn cũng có thể nối nó qua mã. http://aardvarkblogs.wordpress.com/unity-container-tutorials/10-setter-injection/

+0

Cảm ơn bạn đã cung cấp mẹo. Tôi đoán tôi có thể sử dụng điều này như là một giải pháp dự phòng, nhưng theo như tôi có thể thấy điều này đòi hỏi bạn phải tạo ra một thiết lập cho mỗi lớp có sử dụng logger. Tôi tự hỏi nếu đó là một cách để chỉ định này một lần, để tất cả các lớp bằng cách sử dụng logger sẽ được tự động tiêm. – LittleBoyLost

+0

Tôi chưa thử làm như vậy vì vậy tôi không chắc chắn. Tôi nghĩ bạn có thể đăng ký tất cả các lớp học của bạn.Sau đó, phản ánh qua các lớp đã đăng ký và thêm đăng ký tiêm setter nếu loại có một Setter ILogger. –

18

tôi không thích những thuộc tính này cũng

Bạn có thể làm tất cả bằng cách sử dụng Configure phương pháp container đoàn kết:

Đầu tiên đăng ký kiểu

unityContainer.RegisterType<MyInterface,MyImpl>(
        new ContainerControlledLifetimeManager()); 

Nếu bạn có nhiều hàm tạo, bạn sẽ phải thực hiện điều này để Unity gọi hàm khởi tạo không có tham số (nếu không có Unity nào sẽ đặt cho hàm tạo fattest)

unityContainer.Configure<InjectedMembers>() 
          .ConfigureInjectionFor<MyImpl>(
           new InjectionConstructor()); 

Thiết sự phụ thuộc tài sản

unityContainer.Configure<InjectedMembers>() 
        .ConfigureInjectionFor<MyImpl>(
         new InjectionProperty(
          "SomePropertyName", 
           new ResolvedParameter<MyOtherInterface>())); 

Cấu hình phương pháp phụ thuộc

unityContainer.Configure<InjectedMembers>() 
        .ConfigureInjectionFor<MyImpl>(
         new InjectionMethod(
          "SomeMethodName", 
          new ResolvedParameter<YetAnotherInterface>())); 
4

Bạn có thể thử này:

mã này trong MyClass

[InjectionMethod] 
public void Initialize(
       [Dependency] ILogger logger 

và sau đó gọi nó bằng cách:

unitycontainer.BuildUp<MyClass>(new MyClass()); 

thống nhất sau đó sẽ gọi phương thức Initialize với sự phụ thuộc từ container và sau đó u có thể lưu nó trong một biến tư nhân trong MyClass hoặc một cái gì đó ...

7

Ví dụ ban đầu bạn gửi trông rất cồng kềnh, nhưng bạn có thể sử dụng tính năng tự động thực hiện như thế này để giúp làm sạch mã lên:

[Dependency] 
public ILogger Logger { get; set; } 
16

Tôi cũng không phải là một fan hâm mộ lớn của việc sử dụng các thuộc tính nhưng tôi cũng không thích phương thức .Configure<InjectedMembers>() vì bạn bị ràng buộc với tên thuộc tính cụ thể và giá trị cụ thể. Cách tôi tìm thấy mang lại cho bạn sự linh hoạt nhất là tạo chiến lược xây dựng của riêng bạn.

Tôi đã tạo lớp đơn giản này lặp lại các thuộc tính của đối tượng đang được tạo và đặt giá trị thuộc tính của nó nếu loại thuộc tính đó đã được đăng ký với vùng chứa thống nhất.

public class PropertyInjectionBuilderStrategy:BuilderStrategy 
{ 
    private readonly IUnityContainer _unityContainer; 

    public PropertyInjectionBuilderStrategy(IUnityContainer unityContainer) 
    { 
     _unityContainer = unityContainer; 
    } 

    public override void PreBuildUp(IBuilderContext context) 
    { 
     if(!context.BuildKey.Type.FullName.StartsWith("Microsoft.Practices")) 
     { 
      PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(context.BuildKey.Type); 

      foreach (PropertyDescriptor property in properties) 
      { 
       if(_unityContainer.IsRegistered(property.PropertyType) 
        && property.GetValue(context.Existing) == null) 
       { 
        property.SetValue(context.Existing,_unityContainer.Resolve(property.PropertyType)); 
       } 
      } 
     } 
    } 
} 

Bạn đăng ký BuilderStrategy bằng cách tạo UnityContainerExtension. Dưới đây là một ví dụ:

public class TestAppUnityContainerExtension:UnityContainerExtension 
{ 
    protected override void Initialize() 
    { 
     Context.Strategies.Add(new PropertyInjectionBuilderStrategy(Container), UnityBuildStage.Initialization); 
    } 
} 

Đó được đăng ký với container Unity như vậy:

IUnityContainer container = new UnityContainer(); 
container.AddNewExtension<TestAppUnityContainerExtension>(); 

Hope this helps,
Matthew

+0

Đó là một giải pháp tốt đẹp! Tôi làm việc khá tốt cho những gì tôi muốn làm. Tôi sử dụng MEF cho tiêm thường, nhưng trong một ứng dụng giao diện điều khiển tôi muốn sử dụng sự thống nhất, bây giờ tôi không phải đánh dấu tất cả các thuộc tính với nhập khẩu thống nhất! – lukebuehler

+1

Đây là giải pháp có cấu trúc độc đáo. Mối quan tâm duy nhất của tôi sẽ là hiệu suất. Hàm "IsRegistered" sẽ thực sự cố gắng giải quyết mọi thuộc tính công khai. Một cách tốt hơn có thể là chuyển một danh sách các loại để giải quyết vào hàm tạo đối tượng chiến lược và chỉ cố gắng giải quyết các kiểu được chọn tham gia. –

+1

Điều này dường như không hoạt động tốt cùng với PerResolveLifetimeManager vì bạn đang bắt đầu một "giải quyết" mới với mỗi thuộc tính được tiêm. Bất kỳ ý tưởng cho một workaround ở đây? –

4

Với Unity 2.1 này sẽ làm việc cũng như:

var container = new UnityContainer() 
      .RegisterType<ILogger, Logger>() 
      .RegisterType<ISomeInterface, SomeImplementaion>(
           new InjectionProperty("Logger", new ResolvedParameter<ILogger>())); 

Thuộc tính được tiêm của SomeImplementaion lớp học chỉ là

public ILogger Logger { get; set; } 
1

Hãy xem dự án UnityConfiguration để biết cấu hình dựa trên quy ước. Nó hoạt động khá tốt, mặc dù tôi có một vấn đề trong khi tìm kiếm nhiều triển khai bằng cách sử dụng ResolveAll<IType>(). Xem this Question.

container.RegisterInstance(typeof (ILogger), LoggerService.GetLogger()); 
container.Configure(c => c.Scan(scan => 
        { 
         scan.AssembliesInBaseDirectory(a => a.FullName.StartsWith("My.Company")); // Filter out everthing that are not from my assemblies 
         scan.InternalTypes(); 
         scan.With<SetAllPropertiesConvention>().OfType<ILogger>(); 
        })); 
0

Bạn có thể đưa vào lớp của bạn với vùng chứa thống nhất.

ví dụ nếu bạn có một lớp "MyClass" và bạn có sự phụ thuộc vào hai giao diện "IExample1" và "IExample2" và bạn không muốn để xác định tham số cho chúng trong constructor, sau đó làm theo các bước dưới đây

Bước 1. Đăng ký cả các giao diện trong container đoàn kết

IUnityContainer container = new UnityContainer(); 
container.RegisterType<IExample1,Impl1>(); 
container.RegisterType<IExample2,Impl2>(); 
//resolve class MyClass 
var myClass = container.Resolve<MyClass>(); 


Bước 2. lớp học của bạn sẽ trông như thế này

public class MyClass 
{ 
    IExample1 ex1; 
    IExample2 ex2 
    public MyClass(IUnityContainer container) 
    { 
     /* This unity container is same unity container that we used in step 
      1 to register and resolve classes. So you can use this container to resolve 
      all the dependencies. */ 
     ex1= container.Resolve<IExample1>(); // will give you object of Impl1 
     ex2= container.Resolve<IExample2>(); // will give you object of Impl2 
    } 
} 

Bước 3. Bằng cách này, bạn có thể giải quyết bất kỳ số lượng phụ thuộc nào mà không định nghĩa chúng trong hàm tạo.

+1

@Petter Friberg, Cảm ơn bạn đã chỉnh sửa nó. :) –

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