c#中动态加载程序集可通过assembly.load、assembly.loadfrom、assembly.loadfile或assembly.load(byte[])实现;2. assembly.loadfrom会锁定文件且存在加载上下文冲突风险,适合简单场景;3. assembly.load通过全名加载,不锁定文件,适用于gac或应用程序路径下的程序集;4. assembly.load(byte[])从内存加载,避免文件锁定,适合热更新但需手动处理依赖;5. 动态加载后使用gettype获取类型,activator.createinstance创建实例,getmethod和invoke调用方法;6. .net framework中程序集无法单独卸载,需通过appdomain实现隔离与卸载;7. .net core/.net 5+推荐使用assemblyloadcontext,支持细粒度卸载、简化通信并可自定义依赖解析,是appdomain的现代化替代方案。

C#中,
Assembly
Assembly.Load
Assembly.LoadFrom
Assembly.LoadFile
Assembly.Load(byte[])
动态加载程序集并使用其内部类型,一个典型的流程是这样的:
using System;
using System.IO;
using System.Reflection;
public class DynamicAssemblyLoader
{
    public static void LoadAndExecute()
    {
        // 假设我们有一个名为 "MyPlugin.dll" 的程序集,其中包含一个名为 "MyPlugin.MyClass" 的类
        // 这个类有一个公共方法叫做 "Execute"
        string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MyPlugin.dll");
        if (!File.Exists(assemblyPath))
        {
            Console.WriteLine($"错误:未找到程序集文件:{assemblyPath}");
            // 为了演示,这里可以模拟创建一个简单的DLL
            // 实际应用中,你需要确保MyPlugin.dll存在
            Console.WriteLine("请确保有一个名为 'MyPlugin.dll' 的文件在应用程序目录下。");
            Console.WriteLine("示例:一个简单的MyPlugin.dll可以包含以下代码:");
            Console.WriteLine("namespace MyPlugin { public class MyClass { public string Execute(string input) { return $\"Plugin executed with: {input}\"; } } }");
            return;
        }
        try
        {
            // 方式一:使用 Assembly.LoadFrom - 适用于从指定路径加载,会锁定文件
            // Assembly pluginAssembly = Assembly.LoadFrom(assemblyPath);
            // 方式二:使用 Assembly.Load - 如果程序集在GAC或应用程序基路径下,或者你知道它的全名
            // 这里为了演示,我们先加载到内存,避免文件锁定问题,但需要先读取文件到字节数组
            byte[] assemblyBytes = File.ReadAllBytes(assemblyPath);
            Assembly pluginAssembly = Assembly.Load(assemblyBytes);
            Console.WriteLine($"成功加载程序集:{pluginAssembly.FullName}");
            // 获取程序集中的特定类型
            // 假设我们知道要加载的类型是 "MyPlugin.MyClass"
            Type myClassType = pluginAssembly.GetType("MyPlugin.MyClass");
            if (myClassType != null)
            {
                Console.WriteLine($"找到类型:{myClassType.FullName}");
                // 创建该类型的实例
                object instance = Activator.CreateInstance(myClassType);
                // 获取并调用实例上的方法
                MethodInfo executeMethod = myClassType.GetMethod("Execute");
                if (executeMethod != null)
                {
                    // 假设Execute方法接受一个字符串参数并返回一个字符串
                    object result = executeMethod.Invoke(instance, new object[] { "Hello from main app!" });
                    Console.WriteLine($"方法调用结果:{result}");
                }
                else
                {
                    Console.WriteLine("未找到 'Execute' 方法。");
                }
            }
            else
            {
                Console.WriteLine("未找到 'MyPlugin.MyClass' 类型。");
            }
        }
        catch (FileNotFoundException ex)
        {
            Console.WriteLine($"文件未找到错误:{ex.Message}");
        }
        catch (BadImageFormatException ex)
        {
            Console.WriteLine($"程序集格式错误(可能不是有效的.NET程序集):{ex.Message}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"加载或执行程序集时发生错误:{ex.Message}");
            Console.WriteLine(ex.StackTrace);
        }
    }
    // 主函数,用于演示
    public static void Main(string[] args)
    {
        Console.WriteLine("开始动态加载程序集演示...");
        LoadAndExecute();
        Console.WriteLine("动态加载程序集演示结束。");
        Console.ReadKey(); // 等待用户按键,以便查看输出
    }
}
/*
为了运行上述代码,你需要创建一个名为 MyPlugin.dll 的项目:
1. 创建一个新的 C# 类库项目,命名为 MyPlugin。
2. 将以下代码复制到 MyPlugin 项目的 Class1.cs (或任何你喜欢的名称) 中:
namespace MyPlugin
{
    public class MyClass
    {
        public string Execute(string input)
        {
            return $"Plugin executed with: {input} (from MyPlugin.dll)";
        }
    }
}
3. 编译 MyPlugin 项目,然后将生成的 MyPlugin.dll 复制到你的主应用程序(DynamicAssemblyLoader 所在项目)的 Debug/Release 目录下。
*/在我看来,动态加载程序集简直是现代软件设计中实现灵活性和扩展性的杀手锏。你想想看,一个软件产品,如果所有功能都写死在主程序里,那每次更新、增加新功能或者修复bug,都得重新编译、发布整个应用,这对于用户体验和开发效率来说,都是个灾难。
动态加载就完全不同了。我个人觉得它最核心的价值在于:
AppDomain
AssemblyLoadContext
总的来说,动态加载给了我们更多的自由度,让软件变得更“活”,更能适应不断变化的需求。
说实话,刚开始用的时候,这些
Load
Assembly.LoadFrom(string assemblyFile)
LoadFrom
LoadFrom
LoadFrom
Load
InvalidCastException
FileNotFoundException
BadImageFormatException
Assembly.Load(string assemblyName)
Assembly.Load(byte[] rawAssembly)
AppDomain.CurrentDomain.AssemblyResolve
Assembly.LoadFile(string path)
LoadFrom
如何选择?
byte[]
AppDomain
byte[]
AppDomain
AppDomain
AssemblyLoadContext
AppDomain
byte[]
LoadFrom
LoadFrom
Load(string assemblyName)
在我看来,如果你刚接触动态加载,并且遇到了
InvalidCastException
LoadFrom
这部分才是真正把动态能力变现的关键。程序集加载进来后,它只是内存中的一堆二进制数据,你需要通过反射(Reflection)这把“钥匙”去打开它,看看里面有什么,然后才能实例化对象、调用方法。
获取类型(GetType
Assembly
Assembly.GetType(string typeName)
Type
Type myPluginType = loadedAssembly.GetType("MyPlugin.MyClass");
if (myPluginType == null)
{
    Console.WriteLine("类型未找到!");
    return;
}如果不知道完整名称,或者需要遍历程序集中的所有类型,可以使用
Assembly.GetTypes()
Type[]
创建实例(Activator.CreateInstance
Assembly.CreateInstance
Type
Activator.CreateInstance(Type type)
object instance = Activator.CreateInstance(myPluginType);
// 如果构造函数有参数,可以使用 Activator.CreateInstance(Type type, params object[] args)
// object instance = Activator.CreateInstance(myPluginType, new object[] { "some_param" });Assembly.CreateInstance(string typeName)
Assembly
Activator.CreateInstance
object instance = loadedAssembly.CreateInstance("MyPlugin.MyClass");创建出来的实例是
object
调用方法(MethodInfo.Invoke
Type.GetMethod(string methodName)
MethodInfo
GetMethod(string methodName, Type[] parameterTypes)
MethodInfo executeMethod = myPluginType.GetMethod("Execute");
if (executeMethod == null)
{
    Console.WriteLine("方法未找到!");
    return;
}MethodInfo.Invoke(object obj, object[] parameters)
null
object result = executeMethod.Invoke(instance, new object[] { "Data from host app" });
Console.WriteLine($"方法返回:{result}");关于反射的性能和注意事项:
反射虽然强大,但它不是没有代价的。
TargetParameterCountException
ArgumentException
所以,我的建议是,在确实需要灵活性和动态性的场景下使用反射。对于那些性能敏感或类型明确的固定功能,还是老老实实地直接引用和调用吧。有时候,为了那一点点的“酷炫”,付出的调试和维护成本可不低。
说起卸载,这简直是动态加载里最让人头疼的问题之一。在 .NET Framework 中,一个程序集一旦被加载到应用程序域(
AppDomain
这意味着,如果你用
Assembly.LoadFrom
Assembly.Load(byte[])
AppDomain.CurrentDomain
解决方案(.NET Framework):AppDomain
在 .NET Framework 中,唯一的解决方案就是利用
AppDomain
AppDomain
AppDomain
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory; // 设置基路径
// 可以设置私有探测路径等
AppDomain pluginDomain = AppDomain.CreateDomain("PluginDomain", null, setup);AppDomain
MarshalByRefObject
AppDomain
// 假设你的代理类在主程序中,负责加载插件
// public class PluginLoader : MarshalByRefObject { public void LoadPlugin(string assemblyPath) { /* ... */ } }
PluginLoader loader = (PluginLoader)pluginDomain.CreateInstanceAndUnwrap(
    Assembly.GetExecutingAssembly().FullName, // 当前程序集的全名
    typeof(PluginLoader).FullName // 代理类的全名
);
loader.LoadPlugin("MyPlugin.dll"); // 在新的AppDomain中加载插件在
PluginLoader
LoadPlugin
Assembly.LoadFrom
Assembly.Load(byte[])
pluginDomain
AppDomain
AppDomain
AppDomain.Unload(pluginDomain);
Console.WriteLine("插件AppDomain已卸载,程序集已释放。");卸载
AppDomain
AppDomain
AppDomain
AppDomain
.NET Core/.NET 5+ 的替代方案:AssemblyLoadContext
幸运的是,在 .NET Core/.NET 5+ 中,微软引入了
AssemblyLoadContext
AppDomain
AssemblyLoadContext
AssemblyLoadContext
AppDomain
MarshalByRefObject
Load
示例(AssemblyLoadContext
// 这是一个概念性的示例,实际使用需要更严谨的实现 using System.Runtime
以上就是C#的Assembly类如何动态加载程序集?的详细内容,更多请关注php中文网其它相关文章!
 
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
 
                Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号