2012-03-18 21 views
5

Đây là cách tôi muốn nó hoạt độngPhương pháp MEF để lấy giá trị/đối tượng đã xuất hiện (không nhận được Hoặc Tạo) là gì?

container.GetButDoNotCreate<T>(); // should throw (or can return null) if container doesn't contain an instance matching the contract 

var x = container.GetExportedValue<T>(); 

var y = container.GetButDoNotCreate<T>(); // should return the object created in previous step 

Assert.That(x).IsSameAs(y); 

Sự khác biệt là phương pháp này sẽ không tạo ra một thể hiện nếu container không chứa nó. Đó là một sự thuần khiết - có nghĩa là cho tôi vật này nếu nó tồn tại trong thùng chứa. Tôi cần nó cho các bài kiểm tra của tôi, nơi tôi không muốn mã kiểm tra để tạo ra các đối tượng trong thùng chứa sản xuất (nếu chúng không được tạo ra) chỉ sử dụng các đối tượng hiện có. Chỉ mã sản xuất mới thêm/xóa đối tượng vào vùng chứa.

Đăng lên MEF codeplex forum nhưng không có phản hồi. Vì vậy, hy vọng ai đó trên SO có thể có câu trả lời. Ngoài ra, nếu tôi cần viết hàm đó làm phương thức mở rộng ... thì cũng sẽ ổn như một câu trả lời.

+0

Tôi sẽ hỏi tại sao bạn dường như đang thử nghiệm vùng chứa trong các thử nghiệm đơn vị của mình? –

+0

@MatthewAbbott - Tôi đang cố gắng viết các kiểm tra hệ thống ở lớp ViewModel (được xây dựng với thiết kế đầu tiên của ViewModel). Đây không phải là bài kiểm tra đơn vị ... Thay vì thao tác các phần tử giao diện người dùng, tôi muốn tiếp cận vào vùng chứa, lấy khung nhìn và đạt được hiệu ứng tương tự. – Gishu

+0

Thêm ngữ cảnh tại đây - http://caliburnmicro.codeplex.com/discussions/348548 – Gishu

Trả lời

1

Đây là giải pháp của tôi. Lúc đầu, tôi đã thử tạo một phương thức mở rộng. Tôi đã thử nhiều thứ, đọc tài liệu và khám phá các thuộc tính, sự kiện và phương pháp sẵn có trên thùng chứa và danh mục, nhưng tôi không thể làm được gì.

Sau khi suy nghĩ về vấn đề, cách duy nhất tôi có thể đưa ra giải pháp là tạo một thùng chứa có nguồn gốc dựa trên CompositionContainer và triển khai phương thức GetButDoNotCreate.

Cập nhật: Tôi nhận ra sau khi đăng nó rằng giải pháp chỉ hoạt động trong ví dụ đơn giản mà bạn đã đăng ở đó chỉ GetExportedValue được sử dụng để truy xuất các phần đơn giản. Trừ khi bạn sử dụng vùng chứa làm định vị dịch vụ đơn giản cho các phần không có [Nhập] mà sẽ không thực hiện khi các phần có [Nhập] được tạo.

Đây là việc thực hiện:

using System; 
using System.Collections.Generic; 
using System.ComponentModel.Composition.Hosting; 
using System.ComponentModel.Composition.Primitives; 

namespace GetButNotCreate 
{ 
    public class CustomContainer : CompositionContainer 
    { 
     private List<Type> composedTypes = new List<Type>(); 

     public CustomContainer(ComposablePartCatalog catalog) 
      : base(catalog) 
     { 
     } 

     public new T GetExportedValue<T>() 
     { 
      if (!composedTypes.Contains(typeof(T))) 
       composedTypes.Add(typeof(T)); 

      return base.GetExportedValue<T>(); 
     } 

     public T GetButDoNotCreate<T>() 
     { 
      if (composedTypes.Contains(typeof(T))) 
      { 
       return base.GetExportedValue<T>(); 
      } 

      throw new Exception("Type has not been composed yet."); 
     } 
    } 
} 

Nó hoạt động bằng cách ghi đè các phương pháp GetExportedValue để theo dõi các loại đã được sáng tác cho đến nay và sau đó sử dụng này để kiểm tra các loại thành phần trong GetButNotCreate. Tôi đã ném một ngoại lệ như bạn đã đề cập trong câu hỏi của bạn. Tất nhiên, bạn có thể cần phải ghi đè lên quá tải của GetExportedValue (trừ khi bạn không sử dụng chúng, nhưng ngay cả như vậy, tôi sẽ ghi đè lên chúng cho an toàn) và có thể thêm các nhà xây dựng khác và các công cụ nếu bạn sử dụng lớp học. Các tính năng chính của chúng tôi là an toàn. Trong ví dụ này, tôi đã làm tối thiểu để làm cho nó hoạt động.

Dưới đây là các bài kiểm tra đơn vị thử nghiệm phương pháp mới:

using System.ComponentModel.Composition; 
using System.ComponentModel.Composition.Hosting; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 
using System; 

namespace GetButNotCreate 
{ 
    public interface IInterface { } 

    [Export(typeof(IInterface))] 
    public class MyClass : IInterface 
    { 
    } 

    [TestClass] 
    public class UnitTest1 
    {  
     [TestMethod] 
     [ExpectedException(typeof(Exception), "Type has not been composed yet.")] 
     public void GetButNotCreate_will_throw_exception_if_type_not_composed_yet() 
     { 
      var catalog = new AssemblyCatalog(typeof(UnitTest1).Assembly); 
      CustomContainer container = new CustomContainer(catalog); 
      container.ComposeParts(this); 

      var test = container.GetButDoNotCreate<IInterface>(); 
     } 

     [TestMethod] 
     public void GetButNotCreate_will_return_type_if_it_as_been_composed() 
     { 
      var catalog = new AssemblyCatalog(typeof(UnitTest1).Assembly); 
      CustomContainer container = new CustomContainer(catalog); 
      container.ComposeParts(this); 

      var x = container.GetExportedValue<IInterface>(); 
      var y = container.GetButDoNotCreate<IInterface>(); 

      Assert.IsNotNull(y); 
      Assert.AreEqual(x, y); 
     } 
    } 
} 

Nó cho thấy rằng GetButNotCreate sẽ ném một ngoại lệ nếu loại chưa bao giờ được xuất khẩu và rằng nó sẽ trở lại loại này nếu nó đã được đã nhập.

Tôi không thể tìm thấy bất kỳ móc nào để kiểm tra (mà không cần phải phản ánh) để xem liệu MEF có bao gồm một phần hay không, vì vậy giải pháp CustomContainer này sẽ là đặt cược tốt nhất của tôi.

+0

@Giles - đúng phương pháp này sẽ yêu cầu tôi biết tất cả các đường dẫn MEF khác nhau trong đó các đối tượng có thể được xây dựng và chặn các đối tượng đó. Ngoài ra nếu cây đối tượng được xây dựng, điều này sẽ chỉ theo dõi rễ. Thứ hai, tôi không chắc liệu người trung gian này có ngăn chặn việc thu gom rác thải của các bộ phận hay không. – Gishu

+0

Tuy nhiên +1 cho nỗ lực/nỗ lực. Bây giờ tôi đang đặt câu hỏi về nhu cầu .. ngay cả khi ViewModel đã được tạo (trên getExportedValue) từ thử nghiệm (thay vì mã sản xuất), thử nghiệm sẽ thất bại vì nó có thể sẽ không được khởi tạo/kết nối với các cộng tác viên khác. – Gishu

+0

@Gishu sau khi đăng bài viết đầu tiên của tôi, tôi đã cố gắng làm việc với các sự kiện, tôi cũng đã thử một giải pháp khác với các phương pháp mở rộng và tôi thực sự không thể nghĩ ra bất cứ điều gì. Có thể sử dụng phản xạ, bạn có thể tạo một phương thức mở rộng sẽ xem xét bộ sưu tập nội bộ mà MEF đang sử dụng cho phần đó và xem liệu một phần đã có trong bộ sưu tập chưa. – Gilles

0

Tôi nghĩ rằng đáng để có trình bao bọc của riêng bạn trên Vùng chứa. Một cái gì đó như IContainerWrapper và sử dụng nó ở khắp mọi nơi trong mã của bạn.

Với việc này tại chỗ:

  • Nếu bạn có đơn vị xét nghiệm thông thường bạn chỉ có thể tiêm một thể hiện của wrapper, mà phù hợp với nhu cầu của bạn.

  • Nếu bạn muốn truy cập vùng chứa sản xuất nhưng có hành vi được mô tả như trên, thì bạn có thể sử dụng chỉ thị tiền xử lý trong triển khai trình bao bọc sản xuất của mình.

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