2012-03-29 38 views
9

Tôi biết đã có rất nhiều câu hỏi liên quan đến việc tạo tham số constructor bằng MEF, nhưng có một chút khác biệt.MEF: Truyền các tham số hàm tạo khác nhau cho một phần khi sử dụng CreationPolicy.NonShared

Tôi muốn biết rằng có cách nào để chuyển các giá trị tham số khác nhau cho hàm tạo của một phần khi tôi đang sử dụng tổ hợp PartCreationPolicy(CreationPolicy.NonShared)GetExportedValue không?

Ví dụ:

[PartCreationPolicy(CreationPolicy.NonShared)] 
[Export] 
public partial class Foo 
{ 
    [ImportingConstructor] 
    public Foo([Import("SomeParam")]object parameter) 
    { 
     ... 
    } 
} 

và ở một nơi khác ...

container.ComposeExportedValue("SomeParam", "Some value..."); 
var instance = container.GetExportedValue<Foo>(); 

Trong ví dụ trên, tôi có thể sử dụng ComposeExportedValue chỉ một lần, như chạy nó một lần thứ hai sẽ gây ra một ChangeRejectedException.

Vì vậy, câu hỏi của tôi là:

  1. Có cách nào khác để thay đổi giá trị của SomeParam trong kịch bản trên, đối với từng trường hợp mới?
  2. Nếu không, các cách khác có thể thực hiện được gì mà không cần sử dụng bất kỳ khung công tác DI nào khác? Một điều cần lưu ý là tạo một dịch vụ để trưng ra một cái gì đó như System.Collections.Concurrent.ConcurrentQueue nơi tôi enqueue một giá trị tham số trước khi gọi GetExportedValue và sau đó dequeue giá trị trong constructor của một phần. Nhưng đó là một hack và cũng tạo ra nhiều vấn đề hơn là giải quyết.
  3. Nếu câu trả lời cho cả hai câu hỏi trên là không, thì có cách nào khác để thực hiện điều này với sự kết hợp của MEF và một số khung DI/IOC khác không?

Cảm ơn bạn đã được trợ giúp. :)
Kính trọng,
Yogesh Jagota

Trả lời

2

Nếu câu trả lời cho cả hai câu hỏi trên không, sau đó là có cách nào khác để thực hiện điều này với sự kết hợp của MEF và một số khuôn khổ DI/IOC khác?

Tôi nghĩ câu trả lời cho câu hỏi 1 và 2 thực sự là không.

Tôi sẽ thử AutoFac giúp bạn kiểm soát chi tiết hơn và integrates with MEF. Ví dụ, nó cho phép bạn thiết lập đăng ký như thế này để BarBaz trường hợp được Foo dụ của họ với một tham số khác nhau:

builder.Register(c => new Bar(new Foo(param)); 
builder.Register(c => new Baz(new Foo(param2)); 
+0

Tôi đang tìm tích hợp AutoFac/MEF nhưng làm cách nào tôi có thể xử lý đăng ký khi sử dụng 'RegisterComposablePartCatalog'? Tôi không thể sử dụng 'Đăng ký' ở đây vì nó được thực hiện bởi AutoFac tự động. Làm thế nào tôi có thể nói với AutoFac rằng một xuất khẩu nhất định cần phải được khởi tạo bằng cách sử dụng một constructor không mặc định với các tham số mà tôi cung cấp mà không sử dụng '[ImportingConstructor]'? – Yogesh

+0

@Yogesh: Bạn có thể có một số thành phần được đăng ký với AutoFac (khi bạn cần kiểm soát chi tiết) và xuất khác với MEF (khi bạn cần khám phá động của plugin). Nhưng bạn không thể trộn cả hai cho cùng một thành phần. Một tùy chọn khác là chuyển sang AutoFac hoàn toàn; bạn có thể sử dụng [Quét] (http://code.google.com/p/autofac/wiki/Scanning) để có được khám phá động giống như MEF khi cần. –

+0

Nó thực sự hiệu quả. Cách thực hiện nó là sử dụng phương thức 'Update' của' IContainer' cho phép thêm đăng ký mới vào một vùng chứa hiện có. Cảm ơn. :) – Yogesh

1

Nếu bạn muốn sử dụng các trường hợp khác nhau của cùng một giao diện tùy thuộc vào một số logic (áp dụng mẫu chiến lược) trong MEF một cách để sử dụng thuộc tính ExportMetadata. Ví dụ nếu bạn có IDbManager và nếu bạn có hai thực hiện nó nói một Oracle và One Sql sau đó 1. Tạo giao diện siêu dữ liệu mà sẽ giữ metadata

public interface IDbManagerMetadata 
{ 
    DataProvider DataProvider { get; } 
} 

2.Tạo lớp Thuộc tính như sau

[MetadataAttribute] 
public class DbManagerMetadataAttribute : Attribute, IDbManagerMetadata 
{ 
    public DataProvider DataProvider { get; set; } 
} 
  1. Chiến lược dụ

    enum công DataProvider { Oracle, Sql, } [InheritedExport] public interface IDbManager { trống Initialize(); }

    [InheritedExport (typeof (IDbManager))] public class DbManager: IDbManager { công DbManager (DataProvider providerType) { _providerType = providerType; }

    public void Initialize() 
    { 
        Console.WriteLine("provider : {0}", _providerType); 
    } 
    
    public DataProvider _providerType { get; set; } 
    

    }

Và Hai Triển khai khác nhau

[Export(typeof(IDbManager))] 
[DbManagerMetadata(DataProvider = DataProvider.Oracle)] 
public sealed class OracleDataProvider : DbManager 
{ 
    public OracleDataProvider():base(DataProvider.Oracle) 
    { 

    } 
} 

[Export(typeof(IDbManager))] 
[DbManagerMetadata(DataProvider = DataProvider.Sql)] 
public sealed class SqlDataProvider : DbManager 
{ 
    public SqlDataProvider() 
     : base(DataProvider.Sql) 
    { 
    } 
} 

Và bạn có thể quyết định cái nào để sử dụng bằng cách sử dụng giao diện Metadata chúng tôi tạo ra trong bước đầu tiên như trong kho được hiển thị bên dưới

[Export] 
public class Repository 
{ 
    private IDbManager _dbManager; 

    private readonly IEnumerable<Lazy<IDbManager, IDbManagerMetadata>> DbManagers; 

    [ImportingConstructor] 
    public Repository([ImportMany(typeof(IDbManager))]IEnumerable<Lazy<IDbManager, IDbManagerMetadata>> dbManagers) 
    { 
     this.DbManagers = dbManagers; 
     var _dbManager = DbManagers.First(x => x.Metadata.DataProvider == DataProvider.Oracle).Value; 
    } 

    public void Execute() 
    { 
     var oracleDbManager = DbManagers.First(x => x.Metadata.DataProvider == DataProvider.Oracle).Value; 

     oracleDbManager.Initialize(); 

     var sqlDbManager = DbManagers.First(x => x.Metadata.DataProvider == DataProvider.Sql).Value; 

     sqlDbManager.Initialize(); 
    } 
} 
Các vấn đề liên quan