Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#静态构造函数设计问题-需要指定参数_C#_Design Patterns - Fatal编程技术网

C#静态构造函数设计问题-需要指定参数

C#静态构造函数设计问题-需要指定参数,c#,design-patterns,C#,Design Patterns,我对某些类有一个重复出现的设计问题,这些类需要使用一个参数(如配置文件等外部资源的名称)进行一次性初始化 例如,我有一个corelib项目,它提供了应用程序范围的日志记录、配置和通用助手方法。此对象可以使用静态构造函数来初始化自身,但它需要访问无法找到自身的配置文件 我可以看到一些解决方案,但这两个方案似乎都不太正确: 1) 使用带参数的构造函数。但是,需要corelib功能的每个对象也应该知道配置文件的名称,因此必须将其传递给应用程序。另外,如果我将corelib实现为一个单例,我还必须将配置

我对某些类有一个重复出现的设计问题,这些类需要使用一个参数(如配置文件等外部资源的名称)进行一次性初始化

例如,我有一个corelib项目,它提供了应用程序范围的日志记录、配置和通用助手方法。此对象可以使用静态构造函数来初始化自身,但它需要访问无法找到自身的配置文件

我可以看到一些解决方案,但这两个方案似乎都不太正确:

1) 使用带参数的构造函数。但是,需要corelib功能的每个对象也应该知道配置文件的名称,因此必须将其传递给应用程序。另外,如果我将corelib实现为一个单例,我还必须将配置文件作为参数传递给GetInstance方法,我认为这也是不对的

2) 创建通过配置文件或其他外部参数传递的静态属性或方法

我使用了后一种方法,并创建了一个Load方法,它初始化了一个内部类,该类通过构造函数中的配置文件传递。然后通过公共属性mycreib公开这个内部类

public static class CoreLib
{
    private static MyCoreLib myCoreLib;

    public static void Load(string configFile)
    {
        myCoreLib = new MyCoreLib(configFile);
    }

    public static MyCoreLib MyCoreLib
    {
        get { return myCoreLib; }
    }

    public class MyCoreLib
    {
        private string configFile;

        public MyCoreLib(string configFile)
        {
            this.configFile = configFile;
        }

        public void DoSomething()
        {
        }
    }
}
不过我还是不开心。在调用load方法之前,内部类不会初始化,因此需要在访问MyCrelib的任何地方考虑这一点。此外,没有什么可以阻止有人再次调用load方法


任何其他模式或想法如何实现这一点?

您可以将该类设置为单例,从而确保只有一个实例,同时还允许使用构造函数参数。

没有太多替代方案

要么传递内容(在这种情况下,我不会传递字符串,而是创建一个具体的(非静态)CoreLib并传递它),要么按照您的建议执行


不要忘记隐藏mycreib的构造函数。目前它是公共的,这可能是无意的。

当您有这样的全局状态时,您需要初始化,并且需要外部输入来完成初始化(例如配置文件),然后你会被外部代码卡住,这些代码知道输入必须调用Load或Initialize来初始化你的全局状态


但是,您已经正确观察到的问题是,任何人都可以在全局状态被正确初始化之前尝试使用它,这是以这种方式公开它的缺点。解决这个问题的方法是将全局库的所有有状态部分重构为实例类,并将引用传递给t通过应用程序执行。因为您可以控制它的创建和初始化时间,所以现在可以在传递它之前确保它具有有效状态。您可以权衡全局状态的便利性,以获得更好的隔离效果。

您可以使用.net配置系统来执行此操作。最简单的方法是使用ode>元素在web.config文件或appname.exe.config文件中。使用:

ConfigurationManager.AppSettings["property_name"]
访问属性。无论您的代码是在web上下文中运行还是作为windows应用程序运行,配置系统都会找到配置文件并加载所需的值


您还可以使用类型安全配置值和层次结构数据构建更复杂的系统,但我的需求非常简单,因此我在中设置了第一个头痛的问题后就没有探讨这个问题:)

您需要一个公共位置来存储它。即使app.config是一个单独的程序集,您也可以使用它,方法是在库程序集中定义一个config节,并在处理app.config时引用它。或者,您可以只向appSettings添加一个通用设置并引用它,而不使用强类型设置。如果该值是用户输入的,则可以使用独立存储。 最后,您可以在安装时将其放在注册表中一个众所周知的位置

对于代码,下面的代码封装得更好

    public interface ICoreLib
    {
        void SomeMethod();
    }
    public static class CoreLibManager
    {
        private static ICoreLib coreLib;
        private static volatile bool initialized;
        private static readonly object lockObject = new object();
        public static ICoreLib CoreLib
        {
            get
            {
                Inititialize();
                return coreLib;
            }
        }

        /// <summary>
        /// The inititialize.
        /// </summary>
        private static void Inititialize()
        {
            if (initialized)
            {
                lock (lockObject)
                {
                    if (!initialized)
                    {
                        string configFile =  // Fech from common location
                        coreLib = new MyCoreLib(configFile);
                        initialized = true;
                    }
                }
            }
        }

        /// <summary>
        /// The my core lib.
        /// </summary>
        private class MyCoreLib : ICoreLib
        {
            public MyCoreLib(string configPath)
            {
            }
            public void SomeMethod()
            {
            }
        }
    }
公共接口ICoreLib
{
无效方法();
}
公共静态类CoreLibManager
{
私有静态ICoreLib coreLib;
私有静态易失bool初始化;
私有静态只读对象lockObject=新对象();
公共静态ICoreLib CoreLib
{
得到
{
初始化();
返回coreLib;
}
}
/// 
///初始化。
/// 
私有静态void initialize()
{
如果(已初始化)
{
锁定(锁定对象)
{
如果(!已初始化)
{
字符串configFile=//来自公共位置的Fech
coreLib=新的MyCoreLib(configFile);
初始化=真;
}
}
}
}
/// 
///我的核心库。
/// 
私有类MyCoreLib:ICoreLib
{
公共mycreib(字符串配置路径)
{
}
公共方法()
{
}
}
}

好的,谢谢大家的帮助。我重构了CoreLib项目,并将配置处理分解为一个单独的项目。现在我们有了一个用于配置管理的解决方案范围的共享类。该类可以通过用户设置自行处理,该设置通过静态属性ConfigFile公开。如果用户通过某个配置对话框进行更改,此属性还会保留修改后的文件位置。如果配置文件更改,初始化标志也将重置

public interface IConfig
{
    void SomeMethod();
}

public static class ConfigurationManager
{
    private static IConfig config;
    private static volatile bool initialized;
    private static readonly object lockObject = new object();

    public static string ConfigFile
    {
        get { return Properties.Settings.Default.ConfigFile; }
        set
        {
            if (Properties.Settings.Default.ConfigFile == value) return;

            lock (lockObject)
            {
                Properties.Settings.Default.Save();
                initialized = false;
            }
        }
    }

    public static IConfig Config
    {
        get
        {
            Inititialize();
            return config;
        }
    }

    private static void Inititialize()
    {
        lock (lockObject)
        {
            if (initialized) return;

            config = new Configuration(Properties.Settings.Default.ConfigFile);
            initialized = true;
        }
    }
}

internal class Configuration : IConfig
{
    public ClientConfig(string configFile)
    {
        // Parse & validate config file
    }

    public void SomeMethod()
    {
    }
}
因此,现在在启动中,我们首先验证持久化的ConfigFile设置,然后尝试通过manager的Config属性访问配置实例。任何解析异常都可以在这里处理并相应地处理。T
if (!System.IO.File.Exists(ConfigurationManager.ConfigFile))
{
    // Display config file locator dialog
    ConfigurationManager.ConfigFile = someDialog.FileName;
}

try
{
    IConfig config = ConfigurationManager.Config;
}
catch
{
    // Error parsing config file
}