我正在为我的C#IRC Bot实现一个模块系统。这些模块是.dll程序集,存储在子目录“modules”中,它们用于向bot添加功能,例如在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的东西时(具体来说,将新的bot添加到IrcBot.Bots集合,IrcBot.Bots.Add(_configuration.Id, bot);
),辅助appdomain内的IrcBot.Bots
计数会增加只是,而不是我想要它的主appdomain。
在做了一些Console.WriteLining之后,我发现在辅助appdomain中IrcBot.Bots.Count
调用后调用Add
会返回1,并在OnLoad
调用后直接再次调用它在主appdomain中返回0.这会产生灾难性的影响,并导致之后加载的其他模块出现故障。 如何在辅助AppDomain中更改主AppDomain后更新主计数器(或其他内容)?
答案 0 :(得分:0)
正如Juliet所说,AppDomains确实是孤立的,因此其他AppDomains不会显示“静态”变量。解决方案可能是使用跨AppDomain单例,如http://jonathan.dickinsons.co.za/blog/2010/11/cross-domain-singleton-in-c/和http://www.dolittle.com/blogs/einar/archive/2007/05/18/cross-appdomain-singleton.aspx所述。