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