我花了最近几天阅读并尝试了不同的方法来创建和使用我的一个类文件的单例实例,然后在stackoverflow的整个程序生命周期中使用引用,以及很少有其他网站,并且发现有太多的意见,建议和例子可以使我感到有些困惑,特别是当涉及到实际使用单例对象时。
我有一些功能,但我不相信这是最正确的方式,我可能会错过一步。
我的程序中有一个名为clsRegistry的简单类文件,实现为单例。
public sealed class clsRegistry
{
//http://tech.pro/tutorial/625/csharp-tutorial-singleton-pattern
private static clsRegistry RegInstance;
private clsRegistry() { }
public static clsRegistry GetInstance()
{
lock (typeof(clsRegistry))
{
if (RegInstance == null)
{
RegInstance = new clsRegistry();
}
return RegInstance;
}
}
public string dataBase { get; set; }
public string userId { get; set; }
public string passWord { get; set; }
public void ReadKeys()
{
//http://stackoverflow.com/questions/1388787/information-in-registry
RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\Key1\Key2\Key3");
dataBase = key.GetValue("ADODataSource").ToString().Trim();
userId = key.GetValue("ServerUserID").ToString().Trim();
passWord = key.GetValue("ServerPassword").ToString().Trim();
}
} // end class definition
从Main方法调用时正确实现并调用类中的一个公共方法(ReadKeys)
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// create instance of registry class
clsRegistry regData = clsRegistry.GetInstance();
// call method
regData.ReadKeys();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new frmMain());
Application.Run(new frmLogin());
}
}
在创建类的单例后,我有一个小的登录表单加载,我希望单例中的数据库名称显示在表单中,这是我没有优雅代码的地方。
private void frmLogin_Load(object sender, EventArgs e)
{
// create a 'new' instance to the singleton?
clsRegistry regData = clsRegistry.GetInstance();
lblDataBase.Text = regData.dataBase;
}
我是否真的需要为我的单例对象创建另一个引用以便读取某些值(或稍后调用另一个方法)或者我在某个地方错过了一个步骤?我的假设是,一旦我创建了一个类的实例作为单例并且它保持在同一个命名空间中,我就可以访问任何公共值或方法。否?
作为参考,我使用的是Visual Studio 2010和4.0框架(是的,我是另一个经典的VB开发人员,最终跳船)
答案 0 :(得分:2)
首先,Microsoft有guidelines用于在C#中专门实现单例,这非常详细地解释了创建单线程和多线程单例类的最佳方法。
至于你的代码:
调用GetInstance时,不会创建对象的另一个实例。代码返回先前创建的实例。它只实例化一个新的类实例,如果它是null(只有一次)。
你应该让Instance成为一个属性而不是.NET中的方法(它只是更干净)。
在编写.NET代码时你应该坚持使用Pascal案例,如果你正在编写Java代码,我建议你坚持使用camelCase,因为这是该语言的标准外壳。
< / LI> 醇>答案 1 :(得分:1)
首先:在C#中你不需要锁等。只需通过静态初始化创建实例,您就可以进行线程安全,并且可以使用。
public sealed class ClsRegistry
{
private static ClsRegistry RegInstance = new ClsRegistry();
private clsRegistry() { }
public static ClsRegistry Instance {
get { return RegInstance; }
}
public string DataBase { get; set; }
public string UserId { get; set; }
public string PassWord { get; set; }
public void ReadKeys()
{
// ...
}
}
说完之后你可以通过ClsRegistry.Instance
简单地访问单例及其属性/方法,而不需要先将它分配给新的变量:
static void Main()
{
ClsRegistry.Instance.ReadKeys();
// ...
}
和
private void frmLogin_Load(object sender, EventArgs e)
{
lblDataBase.Text = ClsRegistry.Instance.DataBase;
}
请注意,我更改了您的类和属性的名称,以便每个首字母都是大写字母,这是C#中的一种约定
答案 2 :(得分:1)
你需要让单身人士参考它来访问这些值,是的。如果您不想,您不需要将该引用存储在本地变量中,尽管您当然可以。如果您不想,可以直接从实例访问值:
lblDataBase.Text = clsRegistry.GetInstance().dataBase;