C# 即时加载和存储单例

C# 即时加载和存储单例,c#,design-patterns,initialization,singleton,static-constructor,C#,Design Patterns,Initialization,Singleton,Static Constructor,作为尝试对另一个问题提出答案的一部分,我想创建一个自注册单例实例的字典。具体来说,是这样的: public abstract class Role { public static Dictionary<string, Role> Roles = new Dictionary<string, Role>(); protected Role() { _roles.Add(this.Name, this); } pub

作为尝试对另一个问题提出答案的一部分,我想创建一个自注册单例实例的
字典
。具体来说,是这样的:

public abstract class Role
{
    public static Dictionary<string, Role> Roles = new Dictionary<string, Role>(); 

    protected Role()
    {
        _roles.Add(this.Name, this);
    }
    public abstract string Name { get; }
}

public class AdminRole : Role
{
    public static readonly AdminRole Instance = new AdminRole();
    public override string Name { get { return "Admin"; } }
}
如果您没有获得
KeyNotFound
异常(或
null
),则此操作成功


可以显式初始化
Role
(例如
Role.Initialize()
),但不能初始化子类-其思想是能够添加一个子类,以便字典拥有它,而无需更改任何预先存在的内容。

Hm。。有一个真正的问题,用户可以创建他的AppDomains。在当前进程中没有获取所有加载的AppDomain的好方法。我使用网络中创建的坏黑客:。结果代码:

public static void Main()
{
    Console.WriteLine(Role.GetRole("Admin").Ololo);
}

public static class AppDomainExtensions {
    public static List<AppDomain> GetAllAppDomains() {
        List<AppDomain> appDomains = new List<AppDomain>();

        IntPtr handle = IntPtr.Zero;
        ICorRuntimeHost host = (ICorRuntimeHost)(new CorRuntimeHost());
        try
        {
            host.EnumDomains(out handle);
            while (true)
            {
                object domain;
                host.NextDomain(handle, out domain);
                if (domain == null)
                    break;
                appDomains.Add((AppDomain)domain);
            }
        }
        finally
        {
            host.CloseEnum(handle);
        }

        return appDomains;
    }

    [ComImport]
    [Guid("CB2F6723-AB3A-11d2-9C40-00C04FA30A3E")]
    private class CorRuntimeHost// : ICorRuntimeHost
    {
    }

    [Guid("CB2F6722-AB3A-11D2-9C40-00C04FA30A3E")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface ICorRuntimeHost
    {
        void CreateLogicalThreadState ();
        void DeleteLogicalThreadState ();
        void SwitchInLogicalThreadState ();
        void SwitchOutLogicalThreadState ();
        void LocksHeldByLogicalThread ();
        void MapFile ();
        void GetConfiguration ();
        void Start ();
        void Stop ();
        void CreateDomain ();
        void GetDefaultDomain ();
        void EnumDomains (out IntPtr enumHandle);
        void NextDomain (IntPtr enumHandle, [MarshalAs(UnmanagedType.IUnknown)]out object appDomain);
        void CloseEnum (IntPtr enumHandle);
        void CreateDomainEx ();
        void CreateDomainSetup ();
        void CreateEvidence ();
        void UnloadDomain ();
        void CurrentDomain ();
    }   
}

public abstract class Role
{
    private static Dictionary<string, Role> Roles = new Dictionary<string, Role>(); 

    public static Role GetRole(string key) {
        if (Roles.ContainsKey(key))
            return Roles[key];

        foreach (var appDomain in AppDomainExtensions.GetAllAppDomains()) {
            foreach (var assembly in appDomain.GetAssemblies()) {
                var type = assembly.GetTypes().Where(t => t.Name == key + "Role").FirstOrDefault();// (key + "Role", false, true);              

                if (type == null || !typeof(Role).IsAssignableFrom(type))
                    continue;

                Role role = null;

                {
                    var fieldInfo = type.GetField("Instance", BindingFlags.Static | BindingFlags.Public);


                    if (fieldInfo != null) {
                        role = fieldInfo.GetValue(null) as Role;               
                    }
                    else {
                        var propertyInfo = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);

                        if (propertyInfo != null)
                            role = propertyInfo.GetValue(null, null) as Role;
                    }
                }

                if (role == null)
                    continue;

                Roles[key] = role;

                return role;
            }           
        }

        throw new KeyNotFoundException();
    }

    public string Ololo {get;set;}
}

public class AdminRole : Role
{
    public static readonly AdminRole Instance = new AdminRole();

    private AdminRole() {
        Ololo = "a";
    }

}
publicstaticvoidmain()
{
Console.WriteLine(Role.GetRole(“Admin”).Ololo);
}
公共静态类AppDomainExtensions{
公共静态列表GetAllAppDomains(){
List appDomains=新列表();
IntPtr handle=IntPtr.Zero;
ICorRuntimeHost主机=(ICorRuntimeHost)(新的CorRuntimeHost());
尝试
{
主机。枚举域(外句柄);
while(true)
{
对象域;
host.NextDomain(句柄,域外);
如果(域==null)
打破
添加((AppDomain)域);
}
}
最后
{
host.CloseEnum(句柄);
}
返回appDomains;
}
[ComImport]
[Guid(“CB2F6723-AB3A-11d2-9C40-00C04FA30A3E”)]
私有类CorRuntimeHost/:ICorRuntimeHost
{
}
[Guid(“CB2F6722-AB3A-11D2-9C40-00C04FA30A3E”)]
[接口类型(ComInterfaceType.InterfaceSiunknown)]
专用接口ICorRuntimeHost
{
void CreateLogicalThreadState();
void DeleteLogicalThreadState();
void SwitchInLogicalThreadState();
void SwitchOutLogicalThreadState();
void LocksHeldByLogicalThread();
void映射文件();
void GetConfiguration();
void Start();
无效停止();
void CreateDomain();
void GetDefaultDomain();
void EnumDomains(out IntPtr enumHandle);
void NextDomain(IntPtr enumHandle,[marshallas(UnmanagedType.IUnknown)]out object appDomain;
void CloseEnum(IntPtr enumHandle);
void CreateDomainEx();
void CreateDomainSetup();
无效证据();
无效添加域();
void CurrentDomain();
}   
}
公共抽象类角色
{
私有静态字典角色=新字典();
公共静态角色GetRole(字符串键){
if(角色.容器(关键))
返回角色[键];
foreach(AppDomainExtensions.GetAllAppDomains()中的var appDomain){
foreach(appDomain.GetAssemblies()中的var程序集){
var type=assembly.GetTypes()。其中(t=>t.Name==key+“Role”).FirstOrDefault();/(key+“Role”,false,true);
if(type==null | |!typeof(Role).IsAssignableFrom(type))
继续;
Role=null;
{
var fieldInfo=type.GetField(“实例”,BindingFlags.Static | BindingFlags.Public);
如果(fieldInfo!=null){
role=fieldInfo.GetValue(null)作为角色;
}
否则{
var propertyInfo=type.GetProperty(“实例”,BindingFlags.Static | BindingFlags.Public);
if(propertyInfo!=null)
role=propertyInfo.GetValue(null,null)作为角色;
}
}
如果(角色==null)
继续;
角色[关键]=角色;
返回角色;
}           
}
抛出新的KeyNotFoundException();
}
公共字符串Ololo{get;set;}
}
公共类管理员角色:角色
{
公共静态只读AdminRole实例=新AdminRole();
私有管理员角色(){
Ololo=“a”;
}
}
我们所做的:我们迭代所有AppDomain,从中获取所有程序集。对于每个程序集,我们尝试查找类型
Key+“Role”
(基于约定),检查是否存在问题,获取“Instance”字段

现在,关于黑客:这是个坏主意。如果您将创建包含所有已加载域列表的singleton,效果会更好。创建域时,必须将其添加到列表中;卸载时,必须从列表中删除-从角色和其他类中删除属于域的所有类型。它现在的工作原理:不可能卸载AppDomain,因为它的一种类型上总是有一个链接。如果不需要卸载AppDomains,则可以将此代码保持原样


如果您永远不会创建AppDomain,则只能通过
AppDomain.CurrentDomain
程序集进行迭代。

您不想在
角色中更改
字典
-您不想对每个新子类型进行更改,或者您永远不想进行更改?@nsinreal-前者。我希望能够创建一个新的
角色
类型,而无需对其进行子类化。好的,明白了。Reflection@nsinreal-原始询问者不想“扫描整个组件以查找
IRole
s”。我擅长反射,只要它在
角色中是完全独立的。您可以从
Role
类中拉出
Name
,并通过约定命名使其工作。您可以使用方法
GetInstance(key)
或代理类替换字典。调用GetInstance后,首先检查字典。如果没有这样的角色,您将使用GetType(key+“role”)迭代加载到program的所有程序集,并使用它。那太令人印象深刻了。我想我不会提供答案
public static void Main()
{
    Console.WriteLine(Role.GetRole("Admin").Ololo);
}

public static class AppDomainExtensions {
    public static List<AppDomain> GetAllAppDomains() {
        List<AppDomain> appDomains = new List<AppDomain>();

        IntPtr handle = IntPtr.Zero;
        ICorRuntimeHost host = (ICorRuntimeHost)(new CorRuntimeHost());
        try
        {
            host.EnumDomains(out handle);
            while (true)
            {
                object domain;
                host.NextDomain(handle, out domain);
                if (domain == null)
                    break;
                appDomains.Add((AppDomain)domain);
            }
        }
        finally
        {
            host.CloseEnum(handle);
        }

        return appDomains;
    }

    [ComImport]
    [Guid("CB2F6723-AB3A-11d2-9C40-00C04FA30A3E")]
    private class CorRuntimeHost// : ICorRuntimeHost
    {
    }

    [Guid("CB2F6722-AB3A-11D2-9C40-00C04FA30A3E")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface ICorRuntimeHost
    {
        void CreateLogicalThreadState ();
        void DeleteLogicalThreadState ();
        void SwitchInLogicalThreadState ();
        void SwitchOutLogicalThreadState ();
        void LocksHeldByLogicalThread ();
        void MapFile ();
        void GetConfiguration ();
        void Start ();
        void Stop ();
        void CreateDomain ();
        void GetDefaultDomain ();
        void EnumDomains (out IntPtr enumHandle);
        void NextDomain (IntPtr enumHandle, [MarshalAs(UnmanagedType.IUnknown)]out object appDomain);
        void CloseEnum (IntPtr enumHandle);
        void CreateDomainEx ();
        void CreateDomainSetup ();
        void CreateEvidence ();
        void UnloadDomain ();
        void CurrentDomain ();
    }   
}

public abstract class Role
{
    private static Dictionary<string, Role> Roles = new Dictionary<string, Role>(); 

    public static Role GetRole(string key) {
        if (Roles.ContainsKey(key))
            return Roles[key];

        foreach (var appDomain in AppDomainExtensions.GetAllAppDomains()) {
            foreach (var assembly in appDomain.GetAssemblies()) {
                var type = assembly.GetTypes().Where(t => t.Name == key + "Role").FirstOrDefault();// (key + "Role", false, true);              

                if (type == null || !typeof(Role).IsAssignableFrom(type))
                    continue;

                Role role = null;

                {
                    var fieldInfo = type.GetField("Instance", BindingFlags.Static | BindingFlags.Public);


                    if (fieldInfo != null) {
                        role = fieldInfo.GetValue(null) as Role;               
                    }
                    else {
                        var propertyInfo = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);

                        if (propertyInfo != null)
                            role = propertyInfo.GetValue(null, null) as Role;
                    }
                }

                if (role == null)
                    continue;

                Roles[key] = role;

                return role;
            }           
        }

        throw new KeyNotFoundException();
    }

    public string Ololo {get;set;}
}

public class AdminRole : Role
{
    public static readonly AdminRole Instance = new AdminRole();

    private AdminRole() {
        Ololo = "a";
    }

}