2012-12-21 6 views
8

"Autofac tự động chọn hàm tạo với hầu hết các tham số có thể lấy được từ vùng chứa." Tôi muốn nó để làm khác và chọn constructor mặc định để thay thế. http://code.google.com/p/autofac/wiki/AutowiringLựa chọn nhà khai thác tham số Autofac

internal class ParameterlessConstructorSelector : IConstructorSelector 
{ 
    #region Implementation of IConstructorSelector 

    /// <summary> 
    /// Selects the best constructor from the available constructors. 
    /// </summary> 
    /// <param name="constructorBindings">Available constructors.</param> 
    /// <returns> 
    /// The best constructor. 
    /// </returns> 
    public ConstructorParameterBinding SelectConstructorBinding(ConstructorParameterBinding[] constructorBindings) 
    { 
     return constructorBindings.First(); 
    } 

    #endregion 
} 

Khi tôi dây lớp, tôi đã làm điều này:

builder.RegisterType<EmployeeFactory>() 
     .As<IEmployeeFactory>().UsingConstructor(new ParameterlessConstructorSelector()) 
     .SingleInstance(); 

Đầu tiên ràng buộc trong danh sách constructorBindings luôn luôn là một constructor với paremeterless. Không chắc chắn nếu nó được xác định đầu tiên hoặc cách autofac quét các nhà xây dựng nhưng đây là phương pháp tiếp cận đúng để dây cho constructor parameterless?

Cảm ơn

Trả lời

6

Tự động sử dụng phương pháp Type.GetConstructors để khám phá các nhà thầu.

Từ phương pháp documentation:

Các phương thức getConstructors phương pháp không trả lại nhà xây dựng trong một thứ tự cụ thể, chẳng hạn như để tuyên bố. Mã của bạn không được phụ thuộc vào theo thứ tự mà các nhà thầu được trả về, bởi vì thứ tự đó thay đổi.

Vì vậy, thật may mắn khi nó hoạt động với First() trong trường hợp của bạn. Trong một thực hiện đúng bạn cần phải tìm kiếm một cách rõ ràng cho các nhà xây dựng với 0 đối số:

public class DefaultConstructorSelector : IConstructorSelector 
{ 
    public ConstructorParameterBinding SelectConstructorBinding(
     ConstructorParameterBinding[] constructorBindings) 
    { 
     var defaultConstructor = constructorBindings 
      .SingleOrDefault(c => c.TargetConstructor.GetParameters().Length == 0); 
     if (defaultConstructor == null) 
      //handle the case when there is no default constructor 
      throw new InvalidOperationException();     
     return defaultConstructor; 
    } 
} 

Bạn có thể kiểm tra lý thuyết với lớp rất đơn giản này:

public class MyClass 
{ 
    public readonly int i; 

    public MyClass(int i) 
    { 
     this.i = i; 
    } 

    public MyClass() 
    { 
     i = 1; 
    } 
} 

Với thực hiện của bạn:

var builder = new ContainerBuilder(); 
// register 22 for each integer constructor argument 
builder.Register<int>(v => 22); 

builder.RegisterType<MyClass>().AsSelf() 
    .UsingConstructor(new ParameterlessConstructorSelector()); 
var c = builder.Build(); 
var myClass = c.Resolve<MyClass>(); 
Console.WriteLine(myClass.i); 

Kết quả đầu ra là 22 ví dụ: hàm tạo với đối số int được gọi là:

Với thực hiện của tôi:

//... 
builder.RegisterType<MyClass>().AsSelf() 
    .UsingConstructor(new DefaultConstructorSelector()); 
//... 
var myClass = c.Resolve<MyClass>(); 
Console.WriteLine(myClass.i); 

Nó ra 1 ví dụ nhà xây dựng mặc định được gọi.

+0

Tôi biết mình đã may mắn với First() :) Cảm ơn bạn đã giải thích chi tiết. –

+0

Thay vì 'InvalidOperationException', bây giờ Autofac có một lớp' DependencyResolutionException' thích hợp hơn nếu không tìm thấy ctor parameterless. – aholmes

1

Nó sẽ không đơn giản hơn để chỉ đăng ký một cách rõ ràng hàm tạo mặc định?

builder.Register<EmployeeFactory>(c => new EmployeeFactory()) 
    .As<IEmployeeFactory>() 
    .SingleInstance(); 
+1

Có, nó có thể làm việc cho trường hợp đơn giản này. Nhưng nếu bạn đăng ký nhiều loại cùng một lúc (ví dụ: với 'RegisterAssemblyTypes'), việc triển khai một' IConstructorSelector' tùy chỉnh là giải pháp dọn dẹp. – nemesv

+5

Phiên bản mới nhất của autofac có sử dụng quá tải UseConstructor (params Type []) để chọn hàm tạo với các kiểu thích hợp - nếu được gọi không có tham số, nó sẽ chọn hàm tạo mặc định. – Alexander

1

Với phiên bản gần đây của Autofac, điều này rất đơn giản:

builder.RegisterType<EmployeeFactory>() 
     .As<IEmployeeFactory>().UsingConstructor() 
     .SingleInstance(); 

Calling "UsingConstructor" không có tham số có nghĩa là "sử dụng constructor parameterless". Xem https://autofac.org/apidoc/html/EB67DEC4.htm và các trang liên quan.