Dynamically loading Assembly

帅比萌擦擦* 提交于 2021-02-08 05:55:12

问题


In the past, I have written an application that dynamically loads a DLL and all of it's dependencies based upon a value in a database, as below (sanitised some parameters)

VB

Dim oType As System.Type
Dim oAssembly As System.Reflection.Assembly
Dim oObject As System.Object
oAssembly = Assembly.LoadFrom(path)
oType = oAssembly.GetType("LogicValidator")
oObject = Activator.CreateInstance(oType)

oObject.Initialise("param1", "param2", "param3", AuditTrail, UserInfo, workingDir)
Console.WriteLine("Begin processing...")
oObject.ProcessBatch(cm_uid)

Now, when I write something similar in C#, an error is present before building the application, stating the following:

C#

System.Type oType = default(System.Type);
System.Reflection.Assembly oAssembly = default(System.Reflection.Assembly);
System.Object oObject = null;
oAssembly = Assembly.LoadFrom(path);
oType = oAssembly.GetType("LogicValidator");
oObject = Activator.CreateInstance(oType);
oObject.Initialise("param1", "param2", "param3", AuditTrail, UserInfo, workingDir);
Console.WriteLine("Begin processing...");
oObject.ProcessBatch(cm_uid);

Error

'object' does not contain a definition for 'Initialise' and no extension method 'Initialise' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

How can my C# application identify that a method does not exist before compiling, if it is loaded at runtime?

Edit

I have struck out the below for the purposes of helping others who stumble across this question. Whilst it does point to the answer, others have answered it more eloquently. :-)

I would like to add, that the below works - but only if the loaded assemblies dependencies are already present.

var DLL = Assembly.LoadFile(path);
Type type = DLL.GetType("LogicValidator");
dynamic c = Activator.CreateInstance(type);
c.Initialise("param1", "param2", "param3", audit, UserInfo, workingDir);
Console.WriteLine("Begin processing...");
c.ProcessBatch(cm_uid);


回答1:


If you don't know the type at compile time you can make use of the dynamic runtime by declaring the type to be dynamic:

var oAssembly = Assembly.LoadFrom(path);
var oType = oAssembly.GetType("LogicValidator");
dynamic oObject = Activator.CreateInstance(oType);
oObject.Initialise("param1", "param2", "param3", AuditTrail, UserInfo, workingDir);
Console.WriteLine("Begin processing...");
oObject.ProcessBatch(cm_uid);

However, you might consider an approach where the loaded type implements a known interface (which would be declared in an assembly that is referenced both by the add-in and your code):

public interface IProcessor
{
    void Initialise(
        string param1, 
        string param2, 
        string param2, 
        AuditTail auditTrail, 
        UserInfo userInfo, 
        DirectoryInfo workingDir);

    void ProcessBatch(int uid);
}

You can then create an instance as follows and get full IntelliSense support and type checking:

var oAssembly = Assembly.LoadFrom(path);
var oType = oAssembly.GetType("LogicValidator");
IProcessor oObject = Activator.CreateInstance(oType);
oObject.Initialise("param1", "param2", "param3", AuditTrail, UserInfo, workingDir);
Console.WriteLine("Begin processing...");
oObject.ProcessBatch(cm_uid);  



回答2:


You need to change oObject data type to dynamic as follows:

System.Type oType = default(System.Type);
System.Reflection.Assembly oAssembly = default(System.Reflection.Assembly);
dynamic oObject = null;
oAssembly = Assembly.LoadFrom(path);
oType = oAssembly.GetType("LogicValidator");
oObject = Activator.CreateInstance(oType);
oObject.Initialise("param1", "param2", "param3", AuditTrail, UserInfo, workingDir);
Console.WriteLine("Begin processing...");
oObject.ProcessBatch(cm_uid);

More about dynamic: dynamic (C# Reference)




回答3:


You don't need to cast it to dynamic as the other answers say, you can also continue to use reflection which won't invoke the DLR and should be quicker in this instance, especially since you're already loading the necessary reflection objects:

var oAssembly = Assembly.LoadFrom(path);
var oType = oAssembly.GetType("LogicValidator");
var oObject = Activator.CreateInstance(oType);
var oInitialiseMethod = oType.GetMethod("Initialise"); //See note below the code.
var oProcessBatchMethod = oType.GetMethod("ProcessBatch"); //See note below the code.
oInitialiseMethod.Invoke(oObject, "param1", "param2", "param3", AuditTrail, UserInfo, workingDir);
Console.WriteLine("Begin processing...");
oObject.ProcessBatch(cm_uid);

You'll want to use the overload for Type.GetMethod that accepts a Type[] for the function parameters so that the signatures match. Id've done it for you but I don't know what types some of those are.

See https://msdn.microsoft.com/en-us/library/system.type.getmethod(v=vs.110).aspx

As another answer said, though, an interface is a good solution here too - depending on the overall structure of the application and if it's feasible to do for your scenario.



来源:https://stackoverflow.com/questions/40743536/dynamically-loading-assembly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!