Bir .NET derlemesini çalışma zamanında yükleyebilir ve yalnızca adı bilen bir tür başlatabilir miyim?


178

Projede derlemeye bir başvuru eklemeden, yalnızca DLL adı ve sınıf adı varsa, çalışma zamanında bir nesneyi başlatmak mümkün mü? Sınıf bir arabirim uygular, bu yüzden sınıfı başlattığımda, onu arabirime atacağım.

Montaj adı:

Library.dll

Tür adı:

Company.Project.Classname


EDIT: DLL mutlak yolu yok, bu yüzden Assembly.LoadFileişe yaramaz. DLL, uygulama kökünde, system32'de veya hatta GAC'de yüklü olabilir.

Yanıtlar:


221

Evet. Assembly.LoadFromMontajı belleğe yüklemek için kullanmanız gerekir , daha sonra Activator.CreateInstancetercih ettiğiniz türde bir örnek oluşturmak için kullanabilirsiniz . Yansımayı kullanarak önce yazı tipine bakmanız gerekir. İşte basit bir örnek:

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

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

object instanceOfMyType = Activator.CreateInstance(type);

Güncelleme

Derleme dosya adına ve tür adına sahip olduğunuzda, Activator.CreateInstance(assemblyName, typeName).NET türü çözümlemenin bunu bir türe dönüştürmesini istemek için kullanabilirsiniz . Bunu bir try / catch ile sarabilirsiniz, böylece başarısız olursa, başka türlü aranamayan ek montajları özel olarak depolayabileceğiniz bir dizin araması yapabilirsiniz. Bu, bu noktada önceki yöntemi kullanacaktır.


2
Ben dll mutlak yolu yok, bu yüzden assemlby.LoadFile vb. işe yaramaz, başka fikir?
MegaByte

@rp Her zaman yardımcı olmaktan mutluluk duyarız (ve bunu söylemenin sadece bir yılı geç!)
Jeff Yates

2
@MegaByte: LoadFrom, LoadFile'dan farklı. Bağımlılıklarınızı ve bilinen yollardan (GAC, exe dizini vb.) DLL adını çözecektir. Daha fazla bilgi için MSDN'ye bakın.
Jeff Yates

1
Bir şey daha ... (yine ben) Um, sadece tür adı olarak "MyType" a sahip olamazsınız, bunu NAMESPACE izlemelidir. Yani bu daha doğru olur:Type type = assembly.GetType("MyNamespace"+"."+"MyType");
Cipi

1
@Cipi: Teknik olarak, bir tür tam ad alanı adıdır (ad alanı kavramı bir dil kolaylığıdır). CLR içinde ad alanı olmayan bir tür olabilir - Ben sadece aşırı basitleştirilmiş bir örnek veriyordum.
Jeff Yates

36

Farklı Load*yöntemlerin sınırlamalarını düşünün . Gönderen MSDN docs ...

LoadFile, LoadFrom bağlamına dosya yüklemez ve LoadFrom yönteminin yaptığı gibi, yükleme yolunu kullanarak bağımlılıkları çözmez .

Yük Bağlamları hakkında daha fazla bilgi LoadFromdokümanlarda bulunabilir.


19

Aktivatör.CreateInstance çalışması gerekir.

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

Not: Tür adı tam tür olmalıdır.

Misal:

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

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

1
Bu konuda sadece bir not: TypeNametam nitelikli olmalıdır. Buna şöyle demem gerekiyordu: Activator.CreateInstance("MyAssembly","MyAssembly.TypeName") Ve bu bir ObjectHandle. Arayüzünüze inmek için yapmanız gerekenlerObjectHandle.UnWrap()
Anthony Sottile

7

Bu soruyu ve bazı cevapları çok yararlı buldum, ancak yol sorunları vardı, bu yüzden bu cevap bin dizin yolunu bularak yükleme kitaplığını kapsayacaktır.

İlk çözüm:

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);

İkinci çözüm

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");

Arabirimler için aynı prensibi kullanabilirsiniz (bir sınıf oluşturuyorsunuz ancak arayüze döküm yapıyorsunuz), örneğin:

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

Bu örnek web uygulaması içindir, ancak benzer Masaüstü uygulaması için kullanılabilir, örneğin yalnızca yol farklı bir şekilde çözülür, örneğin

Path.GetDirectoryName(Application.ExecutablePath)

5

Bu kolay.

MSDN'den bir örnek:

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);
}

İşte bir referans linki

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


Bu, kodun dinamik yüklenmesini desteklemenin korkunç bir yoludur. MS bizi her zaman çok fazla ayrıntıya girmeye zorlamaktan hoşlanıyor.
Daha temiz

3

Framework v4.5 sürümünden başlayarak, derlemeler içindeki sınıfları kolayca başlatmak için Activator.CreateInstanceFrom () yöntemini kullanabilirsiniz . Aşağıdaki örnek, nasıl kullanılacağını ve parametreleri geçen ve dönüş değeri elde eden bir yöntemin nasıl çağrılacağını gösterir.

    // 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
((ISomeInterface)Activator.CreateInstance(Assembly.LoadFile("somePath").GetTypes()[0])).SomeInterfaceMethod();

2

* Assembly.Load ** yöntemlerini kullanarak bir montaj yükleyebilirsiniz. Activator.CreateInstance yazılımını kullanarak istediğiniz türde yeni örnekler oluşturabilirsiniz. Yüklemek istediğiniz sınıfın tam tür adını kullanmanız gerektiğini unutmayın (örneğin, Namespace.SubNamespace.ClassName ). Yöntem kullanarak ınvokemember ait Tip sınıfına sen türüne yöntemlerini çağırabilirsiniz.

Ayrıca, yüklendikten sonra, tüm AppDomain de kaldırılıncaya kadar bir montajın kaldırılamayacağını göz önünde bulundurun (bu temelde bir bellek sızıntısıdır).


2

Bu tür işlevselliklerin projenize ne kadar içsel olduğuna bağlı olarak, MEF gibi bileşenlerin sizin için yüklenmesini ve birbirine bağlanmasını sağlayacak bir şey düşünmek isteyebilirsiniz .


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

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

dynamic instanceOfMyType = Activator.CreateInstance(type);

Böylece bu şekilde methodinfo alma ve sonra çağırma işlevlerini kullanabilirsiniz. Bu örnek gibi yapacaksınızOfMyType.MethodName (); Ancak Intellisense'i kullanamazsınız çünkü dinamik türler derleme zamanında değil, çalışma zamanında yazılır.


1

Evet, Assembly sınıfında statik Load yöntemini kullanmak ve sonra Load çağrısından size döndürülen Assembly örneğinde CreateInstance yöntemini çağırmak isteyeceksiniz.

Ayrıca, ihtiyaçlarınıza bağlı olarak Assembly sınıfında "Load" ile başlayan diğer statik yöntemlerden birini çağırabilirsiniz.


0

Bu şeyleri şu şekilde yapabilirsiniz:

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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.