Tôi có thể tải một cụm .NET trong thời gian chạy và khởi tạo một kiểu chỉ biết tên không?


178

Có thể khởi tạo một đối tượng trong thời gian chạy nếu tôi chỉ có tên DLL và tên lớp, mà không cần thêm một tham chiếu đến cụm trong dự án? Lớp thực hiện một giao diện, vì vậy một khi tôi khởi tạo lớp, tôi sẽ chuyển nó sang giao diện.

Tên hội:

library.dll

Tên loại:

Company.Project.Classname


EDIT: Tôi không có đường dẫn tuyệt đối của DLL, vì vậy Assembly.LoadFilesẽ không hoạt động. DLL có thể nằm trong root ứng dụng, system32 hoặc thậm chí được tải trong GAC.

Câu trả lời:


221

Đúng. Bạn cần sử dụng Assembly.LoadFromđể tải lắp ráp vào bộ nhớ, sau đó bạn có thể sử dụng Activator.CreateInstanceđể tạo một thể hiện của loại ưa thích của bạn. Bạn sẽ cần phải tìm loại đầu tiên bằng cách sử dụng sự phản chiếu. Đây là một ví dụ đơn giản:

Assembly assembly = Assembly.LoadFrom("MyNice.dll");

Type type = assembly.GetType("MyType");

object instanceOfMyType = Activator.CreateInstance(type);

Cập nhật

Khi bạn có tên tệp lắp ráp và tên loại, bạn có thể sử dụng Activator.CreateInstance(assemblyName, typeName)để yêu cầu độ phân giải loại .NET để phân giải thành loại. Bạn có thể gói nó bằng một lần thử / bắt để nếu nó thất bại, bạn có thể thực hiện tìm kiếm các thư mục nơi bạn có thể lưu trữ cụ thể các tập hợp bổ sung mà nếu không có thể không được tìm kiếm. Điều này sẽ sử dụng phương pháp trước tại thời điểm đó.


2
Tôi không có đường dẫn tuyệt đối của dll, vì vậy lắp ráp.LoadFile ect. Không làm việc, bất kỳ ý tưởng khác?
MegaByte

@rp Luôn sẵn lòng giúp đỡ (và chỉ trễ một năm khi nói như vậy!)
Jeff Yates

2
@MegaByte: LoadFrom khác với LoadFile. Nó sẽ giải quyết các phụ thuộc của bạn và nó sẽ giải quyết tên DLL từ các đường dẫn đã biết (GAC, thư mục exe, v.v.) Xem MSDN để biết thêm thông tin.
Jeff Yates

1
Một điều nữa ... (tôi một lần nữa) Ừm, bạn không thể chỉ có "MyType" làm tên loại, nó phải được theo sau bởi NnamPACE. Vì vậy, điều này sẽ chính xác hơn:Type type = assembly.GetType("MyNamespace"+"."+"MyType");
Cipi

1
@Cipi: Về mặt kỹ thuật, một loại là tên đầy đủ được đặt tên (khái niệm không gian tên là sự tiện lợi về ngôn ngữ). Bạn có thể có một loại không có không gian tên trong CLR - Tôi chỉ cung cấp một ví dụ đơn giản hóa quá mức.
Jeff Yates 18/03

36

Xem xét các hạn chế của các Load*phương pháp khác nhau . Từ các tài liệu MSDN ...

LoadFile không tải các tệp vào ngữ cảnh LoadFrom và không giải quyết các phụ thuộc bằng cách sử dụng đường dẫn tải, như phương thức LoadFrom thực hiện.

Thông tin thêm về Bối cảnh tải có thể được tìm thấy trong các LoadFromtài liệu.


19

Activator.CreateInstance nên hoạt động.

IFace object = (IFace)Activator.CreateInstance( "AssemblyName",
                                                "TypeName" )
                               .Unwrap();

Lưu ý: Tên loại phải là loại đủ điều kiện.

Thí dụ:

var aray = (IList)Activator.CreateInstance("mscorlib","System.Collections.ArrayList").Unwrap();
aray.Add(10);

foreach (object obj in aray)
{
    Console.WriteLine(obj);
}

1
Chỉ cần một lưu ý về điều này: TypeNamephải có đủ điều kiện. Tôi đã phải gọi như thế này: Activator.CreateInstance("MyAssembly","MyAssembly.TypeName") Và điều đó trả về một ObjectHandle. Để truy cập vào giao diện của bạn, bạn cần thực hiệnObjectHandle.UnWrap()
Anthony Sottile

7

Tôi thấy câu hỏi này và một số câu trả lời rất hữu ích, tuy nhiên tôi đã gặp vấn đề về đường dẫn, vì vậy câu trả lời này sẽ bao gồm thư viện tải bằng cách tìm đường dẫn thư mục bin.

Giải pháp đầu tiên:

string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFrom(assemblyPath);
Type T = assembly.GetType("Company.Project.Classname");
Company.Project.Classname instance = (Company.Project.Classname) Activator.CreateInstance(T);

Giải pháp thứ hai

string assemblyName = "library.dll";
string assemblyPath = HttpContext.Current.Server.MapPath("~/bin/" + assemblyName);
Assembly assembly = Assembly.LoadFile(assemblyPath);
(Company.Project.Classname) instance = (Company.Project.Classname) assembly.CreateInstance("Company.Project.Classname");

Bạn có thể sử dụng cùng một nguyên tắc cho các giao diện (bạn sẽ tạo một lớp nhưng chuyển sang giao diện), chẳng hạn như:

(Company.Project.Interfacename) instance = (Company.Project.Interfacename) assembly.CreateInstance("Company.Project.Classname");

Ví dụ này dành cho ứng dụng web nhưng có thể được sử dụng tương tự cho ứng dụng Máy tính để bàn, chỉ có đường dẫn được giải quyết theo cách khác, ví dụ:

Path.GetDirectoryName(Application.ExecutablePath)

5

Dễ thôi.

Ví dụ từ MSDN:

public static void Main()
{
    // Use the file name to load the assembly into the current
    // application domain.
    Assembly a = Assembly.Load("example");
    // Get the type to use.
    Type myType = a.GetType("Example");
    // Get the method to call.
    MethodInfo myMethod = myType.GetMethod("MethodA");
    // Create an instance.
    object obj = Activator.CreateInstance(myType);
    // Execute the method.
    myMethod.Invoke(obj, null);
}

Đây là một liên kết tham khảo

https://msdn.microsoft.com/en-us/l Library / 25y1ya39.aspx


Đó là một cách khủng khiếp để hỗ trợ tải mã động. MS luôn thích buộc chúng ta phải đi vào quá nhiều chi tiết.
Rõ ràng hơn

3

Bắt đầu từ Framework v4.5, bạn có thể sử dụng Activator.CreateInstanceFrom () để dễ dàng khởi tạo các lớp trong các cụm. Ví dụ sau đây cho thấy cách sử dụng nó và cách gọi một phương thức truyền tham số và nhận giá trị trả về.

    // Assuming moduleFileName contains full or valid relative path to assembly    
    var moduleInstance = Activator.CreateInstanceFrom(moduleFileName, "MyNamespace.MyClass");
    MethodInfo mi = moduleInstance.Unwrap().GetType().GetMethod("MyMethod");
    // Assuming the method returns a boolean and accepts a single string parameter
    bool rc = Convert.ToBoolean(mi.Invoke(moduleInstance.Unwrap(), new object[] { "MyParamValue" } ));

2

Đúng. Tôi không có bất kỳ ví dụ nào mà tôi đã thực hiện ngay bây giờ. Tôi sẽ đăng sau khi tôi tìm thấy một số. Về cơ bản, bạn sẽ sử dụng sự phản chiếu để tải lắp ráp và sau đó để kéo bất kỳ loại nào bạn cần cho nó.

Trong khi đó, liên kết này sẽ giúp bạn bắt đầu:

Sử dụng sự phản chiếu để tải các cụm không được tham chiếu trong thời gian chạy


2
((ISomeInterface)Activator.CreateInstance(Assembly.LoadFile("somePath").GetTypes()[0])).SomeInterfaceMethod();

2

Bạn có thể tải một cụm bằng cách sử dụng các phương thức * Association.Load **. Sử dụng Activator.CreateInstance, bạn có thể tạo các phiên bản mới của loại bạn muốn. Hãy nhớ rằng bạn phải sử dụng tên loại đầy đủ của lớp bạn muốn tải (ví dụ Namespace.SubNamespace.ClassName ). Sử dụng phương thức InvokeMember của lớp Type, bạn có thể gọi các phương thức trên kiểu.

Ngoài ra, hãy tính đến khi đã tải, một tập hợp không thể được tải cho đến khi toàn bộ AppDomain cũng được tải (về cơ bản đây là rò rỉ bộ nhớ).


2

Tùy thuộc vào mức độ thực chất của loại chức năng này đối với dự án của bạn, bạn có thể muốn xem xét một cái gì đó giống như MEF sẽ đảm nhiệm việc tải và liên kết các thành phần với nhau.


2
Assembly assembly = Assembly.LoadFrom("MyAssembly.dll");

Type type = assembly.GetType("MyType");

dynamic instanceOfMyType = Activator.CreateInstance(type);

Vì vậy, theo cách này, bạn có thể sử dụng các hàm không phải với lấy phương thức, và sau đó gọi nó. Bạn sẽ làm như thể thể nàyOfMyType.MethodName (); Nhưng bạn không thể sử dụng Intellisense vì các kiểu động được nhập trong thời gian chạy, không phải trong thời gian biên dịch.


1

Có, đó là, bạn sẽ muốn sử dụng phương thức Tải tĩnh trên lớp Hội, và sau đó gọi sau đó gọi phương thức CreatInstance trên phiên bản hội được trả về cho bạn từ lệnh gọi đến Tải.

Ngoài ra, bạn có thể gọi một trong các phương thức tĩnh khác bắt đầu bằng "Tải" trên lớp hội, tùy thuộc vào nhu cầu của bạn.


0

Bạn có thể làm những điều này theo cách này:

using System.Reflection;

Assembly MyDALL = Assembly.Load("DALL"); //DALL name of your assembly
Type MyLoadClass = MyDALL.GetType("DALL.LoadClass"); // name of your class
 object  obj = Activator.CreateInstance(MyLoadClass);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.