2011-02-25 45 views
17

Tôi có giao diện IExample và một tập hợp các lớp ClassOne, ClassTwoClassThree, tất cả được xác định trong các không gian tên khác nhau. Tôi có thể sẽ loại bỏ một trong hai lớp học, hoặc thêm một lớp mới ở một nơi mới, ở giai đoạn sau trong quá trình phát triển.Thực hiện ngay tất cả các lớp đang triển khai một giao diện cụ thể

Bây giờ, tôi muốn tìm tất cả các loại triển khai IExample khi chạy và khởi tạo chúng. (Tôi biết trước rằng không có lớp nào thực hiện IExample sẽ bao giờ cần bất kỳ đối số hàm tạo nào, nhưng tôi không biết cách chỉ định mã đó, vì vậy đó là tôi - không phải trình biên dịch - biết ...)

Đây có phải là khả thi? Làm thế nào để tôi đi về để làm điều đó?

Cập nhật: "không thể tạo một thể hiện của một giao diện" bây giờ tôi đã thử một số trong những phương pháp đề nghị, nhưng trên tất cả trong số họ, dòng Activator.CreateInstance(type), tôi nhận được một System.MissingMethodException vì tôi Đây là mã của tôi:

var tasks = AppDomain.CurrentDomain.GetAssemblies() 
    .SelectMany(a => a.GetTypes()) 
    .Where(t => typeof(IBootstrapperTask).IsAssignableFrom(t)) 

    // This line is where it fails 
    .Select(t => Activator.CreateInstance(t) as IBootstrapperTask) 

    .ToArray(); 
new AutoMapperBootstrapper(tasks).Initialize(); 

Nếu không có sự as khoản tôi không thấy bất kỳ ngoại lệ, nhưng tôi đưa ra một object[], và tôi cần một IBootstrapperTask[] cho các nhà xây dựng trên dòng cuối cùng trong đoạn trích. Tôi đã thử nhiều cách khác nhau để bỏ nó, nhưng không có cách nào làm việc.

Trả lời

28

Điều này có thể được thực hiện bằng Phản xạ. Ví dụ

var interfaceType = typeof(IExample); 
var all = AppDomain.CurrentDomain.GetAssemblies() 
    .SelectMany(x => x.GetTypes()) 
    .Where(x => interfaceType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract) 
    .Select(x => Activator.CreateInstance(x)); 

Lưu ý: Điều này sẽ chỉ tạo ra các trường hợp IExample từ assembly được nạp trong hiện tại AppDomain. Điều này có thể khác với tất cả các assembly được nạp trong tiến trình hiện tại. Tuy nhiên đối với nhiều loại ứng dụng này sẽ tương đương.

+4

Quan trọng hơn mặc dù, nó sẽ chỉ bao gồm các assembly đã được * nạp *. Có thể có những người khác đã được * tham chiếu * nhưng chưa được tải. Cá nhân tôi muốn giữ nó rõ ràng :) –

0

Hãy thử sử dụng sự phản chiếu để có được các loại triển khai IExample. Ví dụ này nhìn vào hội đồng hiện tại nhưng bạn có thể dễ dàng vượt qua một hội đồng khác nhau:

 IEnumerable<Type> types = Assembly.GetExecutingAssembly() 
      .GetTypes().Where(t=>t.GetInterfaces().Where(tt==typeof(IExample)).Count()>0); 
     List<object> objects = new List<object>(); 
     foreach (Type type in types) 
     { 
      objects.Add(Activator.CreateInstance(type)); 
     } 
+0

Tại sao bạn không chỉ gọi 'Chứa'? Ngoài ra, điều đó sẽ không xử lý thừa kế. – SLaks

+1

Điều này sẽ thất bại, vì tôi không thể tạo ra các thể hiện giao diện - tôi phải tạo các thể hiện của các kiểu thực hiện chúng. –

+0

Điều này sẽ không thành công! Tôi đang gọi 't.GetInterfaces()' trên các loại. Tôi đang sử dụng một cái gì đó tương tự trong một dự án của tôi. – Aliostad

8

Bạn sẽ cần phải biết một danh sách các cụm để tìm trong, nhưng sau đó LINQ làm cho nó tương đối dễ dàng:

var instances = (from assembly in assemblies 
       from type in assembly 
       where !type.IsAbstract && 
         type.IsClass && 
         type.IsPublic && 
         !type.IsGenericType && 
         typeof(IExample).IsAssignableFrom(type) 
       let ctor = type.GetConstructor(Type.EmptyTypes) 
       where ctor != null && ctor.IsPublic 
       select (IExample) Activator.CreateInstance(type)) 
       .ToList(); 

Bạn có thể nghĩ ra một số hạn chế khác để thêm, nhưng họ đang khá dễ express :)

instances sau đó sẽ là List<IExample>.

EDIT: Tôi nghi ngờ mã số của tôi sẽ hoạt động ở nơi bạn không làm, bởi vì tôi đặc biệt loại trừ các lớp học không phải là lớp học. Tôi đoán là mã của bạn đang cố gắng tự khởi tạo giao diện, tức là khi ttypeof(IBootstrapperTask).

+0

Cảm ơn bạn đã trả lời - vui lòng xem cập nhật của tôi để biết thêm thông tin. –

+0

@Tomas: Đã chỉnh sửa. Bạn đã thử giải pháp của tôi chưa? (Thay đổi dòng cuối cùng thành 'ToArray' nếu bạn muốn.) Phải thừa nhận rằng tôi không thể thấy tại sao' as' sẽ tạo ra bất kỳ sự khác biệt nào với mã ban đầu của bạn ... –

+0

Cảm ơn bạn. Khi tôi xem xét kỹ hơn mã của bạn, tôi nhận thấy các yêu cầu rõ ràng là công khai, không trừu tượng và với một hàm tạo và cũng đã triển khai chúng trong mã của tôi. Bây giờ phần cụ thể này hoạt động, nhưng tôi có các vấn đề khác (có thể không liên quan), vì vậy tôi không thể thấy điều này có thực sự hoạt động hay chỉ ném một ngoại lệ khác. –

5

Bạn có cần điều này xảy ra động không? Có bao giờ bạn có thể có một cái mà bạn không muốn tạo không? Dường như với tôi rằng đây là một trường hợp tốt cho tiêm phụ thuộc (có thể được cấu hình). Ví dụ: Unity có phương thức ResolveAll.

Từ liên kết ở trên;

IEnumerable<IMyObject> objects = myContainer.ResolveAll<IMyObject>(); 
+0

Chỉ với thông tin ví dụ giới hạn mà tôi đưa ra trong câu hỏi của tôi, đây là một đối số hợp lệ, nhưng trong trường hợp này DI không áp dụng. –

+0

Ha - chỉ vì tôi đã quá nhanh để loại bỏ DI, nó chỉ ra đây là nơi tôi sẽ kết thúc anyway ...: P Cảm ơn! Tuy nhiên, tôi sẽ không đánh dấu đây là câu trả lời, đơn giản vì nó không thực sự trả lời câu hỏi ("làm cách nào để tìm tất cả các lớp thực hiện giao diện này động?"), Mặc dù nó giải quyết được vấn đề thực tế của tôi. –

+0

+1 Cảm ơn rất nhiều! Tôi đã xây dựng một dự án bằng cách sử dụng Caliburn.Micro để xử lý tất cả những thứ liên quan đến MVVM của tôi và nó không bao giờ đến với tôi rằng tôi có thể sử dụng nó để giải quyết vấn đề này! Bất cứ ai khác thích giải pháp này nên thử khung này. – CuddleBunny

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