我正在为我的 C# IRC Bot 实现一个模块系统。这些模块是 .dll 程序集,它们存储在子目录“模块”中,它们用于向机器人添加功能,例如在 IRC 上添加额外的命令。这些模块设计为在运行时加载和卸载,因此我可以更新机器人或修复错误,而无需重新启动整个应用程序。
目前,模块系统AppDomain
为每个要加载的模块创建一个新的,并CreateInstanceFromAndUnwrap
在一个名为ModuleHelper
.
AppDomain domain = AppDomain.CreateDomain(name, null, new AppDomainSetup
{
ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
DisallowApplicationBaseProbing = true,
PrivateBinPathProbe = ModuleDirectory,
PrivateBinPath = ModuleDirectory,
ShadowCopyDirectories = ModuleDirectory,
CachePath = Path.Combine(ModuleDirectory, "cache"),
ShadowCopyFiles = bool.TrueString
});
ModuleProxy proxy = null;
try
{
proxy = (ModuleProxy)domain.CreateInstanceFromAndUnwrap(location, AssemblyName.GetAssemblyName(location).Name + ".Module");
proxy.OnLoad();
}
catch
{
AppDomain.Unload(domain);
throw;
}
此代理继承自MarshalByRefObject
.
public abstract class ModuleProxy : MarshalByRefObject
{
internal protected virtual void OnLoad()
{
}
internal protected virtual void OnUnload()
{
}
}
OnLoad
并OnUnload
在加载或卸载模块时调用。模块也继承自MarshalByRefObject
外部程序集,例如模块中的此类,ConfigurationReader.dll
.
public class Module : ModuleProxy
{
private Configuration _configuration = new Configuration();
protected override void OnLoad()
{
string fileName = Path.Combine(ModuleHelper.ModuleDirectory, AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).Name + ".conf");
_configuration.ReadAndLoadConfiguration(fileName);
IrcBot bot = new IrcBot(_configuration);
if (_configuration.Perform != null)
{
bot.EventManager.OnRegister += PerformOnRegister;
}
if (!string.IsNullOrWhiteSpace(_configuration.IdentifyMatchPeer + _configuration.IdentifyMatchText + _configuration.IdentifyPassword))
{
bot.EventManager.OnNotice += IdentifyOnNotice;
}
IrcBot.Bots.Add(_configuration.Id, bot);
IrcBot.Bots[_configuration.Id].Start();
}
...
...
...
问题是,当我修改属于主 appdomain 的内容时(特别是,将新机器人添加到 IrcBot.Bots 集合中IrcBot.Bots.Add(_configuration.Id, bot);
),IrcBot.Bots
计数仅在辅助 appdomain 内增加,而不是我想要的主 appdomain .
做了一点Console.WriteLining后发现,在二级appdomain调用IrcBot.Bots.Count
后调用返回1,在主appdomain调用返回0后直接再次调用。这样的后果是灾难性的,并导致其他模块加载后发生故障。在辅助 AppDomain 中更改后,如何更新主 AppDomain 中的机器人计数(除其他外)?Add
OnLoad