1

C# IRC ボットのモジュール システムを実装しています。モジュールは、サブディレクトリ "modules" に格納されている .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()
    {
    }
}

OnLoadOnUnloadモジュールがロードまたはアンロードされるときに呼び出されます。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 を少し実行したIrcBot.Bots.CountAdd、セカンダリ appdomain での呼び出しが 1 を返した後にOnLoad呼び出し、メイン appdomain での呼び出しが 0 を返した直後にもう一度呼び出すことがわかりました。これは悲惨な結果をもたらし、他のモジュールを引き起こします後でロードされて誤動作します。セカンダリ AppDomain で変更した後、メイン AppDomain のボット数を (とりわけ) 更新するにはどうすればよいですか?

4

1 に答える 1

0

Julietが言ったように、AppDomainは実際に分離されているため、「静的」変数は他のAppDomainからは見えません。http://jonathan.dickinsons.co.za/blog/2010/11/cross-domain-singleton-in-c/およびhttp://www.dolittleで説明されているように、解決策はクロスAppDomainシングルトンを使用することです。 com / blogs / einar / archive / 2007/05/18/cross-appdomain-singleton.aspx

于 2011-07-16T09:03:40.473 に答える