跨应用程序域(AppDomain)的单例(Singleton)实现
转载自:
跨应用程序域(AppDomain)的单例(Singleton)实现 - CorePlex代码库 - CorePlex官方网站,Visual Studio插件,代码大全,代码仓库,代码整理,分享,为打造最有价值的在线代码库而不懈努力
http://www.udnz.com/code-2882.htm
工作中基于插件模式,特别是插件可能不稳定,导致主程序进程终止时,我们往往使用应用程序域来隔离插件和主程序,但此时如果主程序中有单例(Singleton)实现,那在不同的AppDomain里访问时,会导致单例失效。为解决这一问题,从网上找到了如下代码。主要思想是:我们使用一个特定名称的应用程序域来创建和持有这些单例。每当我们需要某个单例时,便从这个特定的应用程序域中获取。
注意:由于跨AppDomain创建单例,因此单例的类的构造函数必须设置为公共的无参构造函数,这一点应当留意。
see:http://www.dolittle.com/blogs/einar/archive/2007/05/18/cross-appdomain-singleton.aspx
代码正文
/* ************************* * Cross AppDomain Singleton * ************************* * * The solution we want is that the singleton class is created in a * given AppDomain and in all other AppDomains we get a transparent * proxy to that singleton. * * In order to do this we need to have the ability to enumerate * through existing AppDomains in order to create an instance in the * correct AppDomain (at least I found this to be cool way of doing it). * I came across a thread on microsoft.public.dotnet.framework.clr * that gave me a good solution (http://groups.google.com/group/microsoft.public.dotnet.framework.clr/browse_frm/thread/dba9c445ad8d5c3/9df14bf0af393c28?lnk=st&q=enumerate+appdomain+group%3Amicrosoft.public.dot%20net.*&rnum=5#9df14bf0af393c28) * * You need to add a reference to the MSCOREE.TLB which is situated * in the .net directory (c:\windows\microsoft.net\framework\v2.0.50727, * depends on your runtime version). When you add a reference to it * you'll get an Interop.mscoree.dll added to your output directory. * You will have to have this alongside your deployment if you're going * to use this in a solution. */ /// <summary> /// Cross AppDomain Singleton /// </summary> /// <typeparam name="T"></typeparam> public class SingletonDomain<T> : MarshalByRefObject where T : new() { private static readonly string AppDomainName = "SingletonAppDomain"; private static T _instance; private static AppDomain GetAppDomain(string friendlyName) { IntPtr enumHandle = IntPtr.Zero; mscoree.CorRuntimeHost host = new mscoree.CorRuntimeHost(); try { host.EnumDomains(out enumHandle); object domain = null; while (true) { host.NextDomain(enumHandle, out domain); if (domain == null) { break; } AppDomain appDomain = (AppDomain)domain; if (appDomain.FriendlyName.Equals(friendlyName)) { return appDomain; } } } finally { host.CloseEnum(enumHandle); Marshal.ReleaseComObject(host); host = null; } return null; } public static T Instance { get { if (null == _instance) { AppDomain appDomain = GetAppDomain(AppDomainName); if (null == appDomain) { AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation; setup.ApplicationName = "SingletonAppDomain"; // Set up the Evidence Evidence evidence = new Evidence(AppDomain.CurrentDomain.Evidence); appDomain = AppDomain.CreateDomain(AppDomainName, evidence, setup); } Type type = typeof(T); T instance = (T)appDomain.GetData(type.FullName); if (null == instance) { instance = (T)appDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName); appDomain.SetData(type.FullName, instance); } _instance = instance; } return _instance; } } }