2012-01-13 9 views
16

Tôi muốn tạo một cá thể của một lớp bằng cách sử dụng sự thống nhất trong đó lớp có hai hàm tạo với cùng số tham số.Giải quyết cá thể với nhiều hàm tạo sử dụng sự thống nhất

Đây là instantiation:

_unityContainer.Resolve<IGradeType>(new ParameterOverride("gradeTypeStringFromXmlFile", gradeTypeStringFromXmlFile)); 

Và đây là các nhà thầu:

public GradeType(string gradeTypeStringFromXmlFile) 
    { 
     _gradeTypeStringFromXmlFile = gradeTypeStringFromXmlFile; 
    } 

    public GradeType(Enum.GradeType gradeType) 
    { 
     _gradeType = gradeType; 
    } 

Nếu tôi cố gắng để làm điều này tôi nhận được một ngoại lệ nói Loại GradeType có nhiều nhà xây dựng có độ dài 1 Không thể phân biệt.

Tôi có thể đặt thuộc tính [InjectionConstructor] trên một hàm tạo để làm cho nó hoạt động với một hàm, nhưng sau đó tôi không thể tạo một cá thể với sự thống nhất bằng cách sử dụng hàm tạo khác.

Có cách nào để có nhiều nhà xây dựng với số tham số bằng nhau và vẫn sử dụng sự thống nhất để tạo các cá thể không?

+0

tại sao không sử dụng 'Enum.Parse' trên chuỗi classType trước khi tạo lớp? – jgauffin

+0

nó chỉ cảm thấy giống như một thiết kế trực quan mà lớp GradeType chuyển đổi chuỗi. – FatAlbert

+1

Nó có vẻ là một giải pháp dễ vỡ đối với tôi vì bất kỳ giá trị không tồn tại nào sẽ ném một ngoại lệ hoặc ẩn một lỗi. – jgauffin

Trả lời

26

Có thể cho Unity biết nên sử dụng hàm tạo nào, nhưng bạn chỉ có thể thực hiện việc này khi bạn đăng ký loại của mình với InjectionConstructor. Nếu bạn muốn sử dụng cả hai constructor nó thậm chí còn phức tạp bởi vì bạn phải đặt tên đăng ký của bạn và sử dụng tên đó khi giải quyết.

mẫu được xây dựng với phiên bản Unity 2.1.505:

var continer = new UnityContainer(); 

continer.RegisterType<IGradeType, GradeType>("stringConstructor", 
    new InjectionConstructor(typeof(string))); 

continer.RegisterType<IGradeType, GradeType>("enumConstructor", 
    new InjectionConstructor(typeof(EnumGradeType))); 

IGradeType stringGradeType = continer.Resolve<IGradeType>("stringContructor" , 
    new DependencyOverride(typeof(string), "some string")); 

IGradeType enumGradeType = continer.Resolve<IGradeType>("enumConstructor", 
    new DependencyOverride(typeof(EnumGradeType), EnumGradeType.Value)); 
+0

chỉ là những gì tôi đang tìm kiếm! thanks – FatAlbert

+1

Một câu hỏi: Khi ghi đè phụ thuộc, chúng tôi buộc phải gọi giải quyết rõ ràng trên vùng chứa? Nhưng nó không phải là xấu để gọi rõ ràng container.Resolve trong mã ứng dụng của bạn? Rất tiếc, thực sự là hai câu hỏi ;-) – Legends

0

Xóa một hàm tạo và truyền chuỗi đó vào ô, hoặc ngược lại, rồi giải quyết bằng cách sử dụng vùng chứa.

+0

Bạn không thể bỏ một chuỗi vào một enum. – jgauffin

+0

Enum.Parse - như bạn đã nói – Jason

+0

Chuỗi từ xml hoàn toàn khác với enum (chuỗi bằng tiếng Thụy Điển). Tuy nhiên, những gì tôi yêu cầu là nếu nó có thể có nhiều nhà xây dựng với số lượng thông số bằng nhau và vẫn sử dụng sự thống nhất để tạo ra các cá thể? – FatAlbert

1

Một lựa chọn thay thế sử dụng Reflection và làm theo tấm Strategy Pattern.

1) Tạo một lớp cơ sở cho lập luận của các nhà xây dựng

public abstract class ConstructorArgs 
{ 
} 

2) Tạo một chuỗi các lớp đối số bê tông khác nhau:

public class StringArg : ConstructorArgs 
{ 
    public string _gradeTypeStringFromXmlFile { get; set; } 

    public StringArg (string gradeTypeStringFromXmlFile) 
    { 
     this._gradeTypeStringFromXmlFile = gradeTypeStringFromXmlFile ; 
    } 
} 

public class EnumArg : ConstructorArgs 
{ 
    public Enum.GradeType _gradeType { get; set; } 

    public EnumArg (Enum.GradeType gradeType) 
    { 
     this._gradeType = gradeType ; 
    } 
} 

3) Bây giờ trong lớp GradeType bạn tạo ra các phương pháp cần thiết cho Reflection. ParseArguments quét các arg cho các thuộc tính và đối với mỗi thuộc tính mà nó tìm thấy, nó sao chép giá trị của nó vào thuộc tính tương ứng của GradeType bằng cách sử dụng SetProperty.Kể từ khi nó sử dụng tên tài sản cho phù hợp, điều quan trọng là để giữ cho tên thuộc tính như nhau trên cả GradeType và ConstructorArgs bê tông:

 private void SetProperty(String propertyName, object value) 
     { 
      var property = this.GetType().GetProperty(propertyName); 
      if (property != null) 
       property.SetValue(this, value); 
     } 
     private void ParseArguments(ConstructorArgs args) 
     { 
      var properties = args.GetType().GetProperties(); 
      foreach (PropertyInfo propertyInfo in properties) 
      { 
       this.SetProperty(propertyInfo.Name, 
        args.GetType().GetProperty(propertyInfo.Name).GetValue(args)); 
      } 
     } 

4) Trong lớp GradeType bạn tạo các thuộc tính tương ứng (nhớ rằng bạn phải sử dụng chính xác cùng tên và các loại mà bạn sử dụng trong ConstructorArgs bê tông nhưng bạn có thể sử dụng bất kỳ bổ truy cập mà bạn thích)

public string _gradeTypeStringFromXmlFile { get; set; } 
    public Enum.GradeType _gradeType { get; set; } 

5) Tạo một constructor cho lớp GradeType của bạn với một tham số kiểu ConstructorArgs:

public GradeType(ConstructorArgs args) 
    { 
     this.ParseArguments(args); 
    } 

6) Bây giờ bạn có thể đăng ký GradeType trong Unity sử dụng một constructor đơn nhưng bạn có thể vượt qua trong các loại khác nhau như các đối số khi giải quyết nó:

_unityContainer.RegisterType<IGradeType, GradeType>(
     new InjectionConstructor(typeof(ConstructorArgs))); 

    var args1 = new StringArg(gradeTypeStringFromXmlFile); // string 
    IGradeType gradeType1 = _unityContainer.Resolve<IGradeType>(
     new ResolverOverride[]{new ParameterOverride("args", args1)}); 

    var args2 = new EnumArg(gradeType); // enum 
    IGradeType gradeType2 = _unityContainer.Resolve<IGradeType>(
     new ResolverOverride[]{new ParameterOverride("args", args2)}); 

Nếu bạn đang có kế hoạch liên tục giải quyết kiểu của bạn trong một lần lặp cách tiếp cận đó có thể không lý tưởng, vì Reflection đi kèm với một hình phạt hiệu suất.