2

I have spent last couple of days reading about and trying different methods for creating and using a singleton instance of one of my class files and then using the reference as I need throughout the life of the program here on stackoverflow and well as a few other sites, and have found that there are soooo many opinions, suggestions and examples that work that I have gotten a little confused, especially when it comes to actually using the singleton object.

I have something that functions but I do not believe it is the most correct way and that I may be missing a step.

I have a simple class file in my program called clsRegistry implemented as a singleton.

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

Which when called from the Main method implements correctly and calls the one public method (ReadKeys) in the class

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());
  }
}

After the singleton of the class is created I have a small login form loading and I want the database name from the singleton to display in the form and this is where I have less than elegant code.

private void frmLogin_Load(object sender, EventArgs e)
{
  // create a 'new' instance to the singleton?
  clsRegistry regData = clsRegistry.GetInstance();

  lblDataBase.Text = regData.dataBase;
}

Do I really need to create another reference to my singleton object in order to read some values (or later on call another method) or am I missing a step some where? I am operating under the assumption that once I create an instance of a class as a singleton and it remains within the same namespace I can access any public value or method. No?

For reference I am using Visual Studio 2010 and the 4.0 framework (and yes I am another classic VB developer thats FINALLY jumping ship)

Kini
  • 23
  • 3
  • 2
    I think you are doing it right. Just because you've created an instance of the singleton object doesn't mean that you should be able to use a reference to it out of scope--it's not a global variable. If you want to use the instance in another class, you will have to gain a reference to it like you are doing here. You're not creating a "new" singleton, just getting reference to the existing one. At least that is my understanding. – eddie_cat Jul 15 '14 at 20:48
  • 3
    You are not 'creating' a new instance, just getting a _reference_ to the single instance. – H H Jul 15 '14 at 20:49
  • 1
    if you've spent the last days reading about it you must have stumbled across [Jon Skeets suggestion](http://csharpindepth.com/articles/general/singleton.aspx)? That's a really neat implementation according to me – default Jul 15 '14 at 20:49
  • 1
    Be sure to read [this question](http://stackoverflow.com/questions/8209243/when-is-locking-on-types-a-good-idea) – H H Jul 15 '14 at 20:54
  • You shouldn't be exposing `ReadKeys` publicly, you should just be initializing the data in the constructor. Your properties also shouldn't have setters. On top of that, are you really sure that you want to be storing usernames and passwords in the registry, that doesn't sound secure. – Servy Jul 15 '14 at 20:56

3 Answers3

2

First of all, Microsoft has guidelines for implementing a singleton specifically in C# that explains in great detail the best way to create a single and multi-threaded singleton class.

As far as your code:

  1. You are not creating another instance of your object when you call GetInstance. The code returns the previously created instance. It only instantiates a new instance of the class if it is null (just once).

  2. You should make Instance a property instead of a method in .NET (it's just cleaner).

  3. You should stick to Pascal case when writing .NET code, if you were writing Java code, I'd suggest you stick to camelCase because that is the standard casing for the language.

Alan
  • 7,875
  • 1
  • 28
  • 48
1

First of all: In C# you don't need locks etc for this. Just create the instance through static initialization and you're threadsafe and good to go.

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()
    {
        // ...
    }
}

Having that said you can then simply access the singleton and its properties/methods through ClsRegistry.Instance without the need to assign it to a new variable first:

static void Main()
{
    ClsRegistry.Instance.ReadKeys();
    // ...
}

and

private void frmLogin_Load(object sender, EventArgs e)
{
    lblDataBase.Text = ClsRegistry.Instance.DataBase;
}

Please note that I changed the names of your class and properties so that each first letter is a capital, which is kind of a convention in C#

H H
  • 263,252
  • 30
  • 330
  • 514
Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
  • 2
    While this is certainly a simpler way of defining the singleton, it in no way answers the actual question that is asked. – Servy Jul 15 '14 at 20:51
  • @Servy This might be true but it definitely is a starting point for OP. Or do you expect me to go through all the code that he posted and rewrite it for him? From people who write computer programs I can expect some thinking of their own, no? – Dennis Traub Jul 15 '14 at 20:53
  • 2
    It's an unrelated tangent. Certainly something appropriate to point out in comments, as many other people did before you even posted your answer, but it's not appropriate to post an answer without answering the question. – Servy Jul 15 '14 at 20:54
  • This answer doesn't deserve to be down-voted so hard. While it doesn't address the question directly, it's a little know fact that this pattern is actually thread safe. The more traditional one where the object is instantiated in the property requires a manual lock to be that. – Gerben Rampaart Jul 15 '14 at 20:56
  • @GerbenRampaart The post *absoulutely* deserves to be downvoted because *it's not an answer*. When you post an answer it's important to *answer the question*. If you would like to provide useful information that is tangential to the question itself then the appropriate place to do so is in comments, where a bunch of other people included all of this information already, before this answer was even posted. On top of that, Dennis isn't even a new user. He knows better. – Servy Jul 15 '14 at 20:59
  • @Servy, point out to me the actual question would you? I count several. It comes down to this: I don't understand the correct way to construct a singleton. Dennis answers that. "I have something that functions but I do not believe it is the most correct way and that I may be missing a step." <- that's what came closest to the actual question. So, I disagree this isn't, at least part, of the answer. – Gerben Rampaart Jul 15 '14 at 21:03
  • 2
    @GerbenRampaart If you want to know what the actual question is just do a simple ctrl + F for `?` and you can see right where the question is. To quote it for you: "Do I really need to create another reference to my singleton object in order to read some values [...]?" He's not asking for best practices on how to create a singleton. He's asking how to use the singleton he's already created. – Servy Jul 15 '14 at 21:08
  • @GerbenRampaart Never mind. As of Servy's profile he downvoted 10,230 times already. I guess his tolerance threshold is quite low. – Dennis Traub Jul 15 '14 at 21:15
  • @Servy Stop trying to be degrading with 'ctrl-f' like comments. It's boring and it doesn't make me respect you more, if that was at all your intent. Once again; the first encounter is: "I have something that functions but I do not believe it is the most correct way". That alone you are very welcome to answer as a user. Maybe it won't be accepted, but that's the poster's matter. – Gerben Rampaart Jul 15 '14 at 21:16
  • @DennisTraub You're right, I think I've carried it on for too long already. Out of respect to Servy I'll let him have the last say, and I'll delete these comments. – Gerben Rampaart Jul 15 '14 at 21:17
  • 1
    @GerbenRampaart So you can't find the question, I told you how to find it, you still can't find it, and I'm being degrading? To the section you quoted, what reason do you have to belive that "what isn't working" is the singleton itself? He made it clear that he thinks his singleton works, and he's concerned about how he's calling it. *That* is what he appears to "not believe it is the most correct way". This perspective is of course supported by him saying so *in the actual question that he's asking* that you appear to have not bothered to try to find or read. – Servy Jul 15 '14 at 21:29
  • I have found it and read it. But you know that, it's just your style of communication to imply I didn't. This *"I am operating under the assumption that once I create an instance of a class as a singleton and it remains within the same namespace I can access any public value or method. No?"* simply means: **Forget the rest of my code and point me to a correct way to write and consume a singleton pattern.** We might disagree, but that's just going to have to be that then. – Gerben Rampaart Jul 15 '14 at 21:40
  • Maybe you don't need locks for this application but the first sentence is very wrong in general. – H H Jul 16 '14 at 08:02
  • @HenkHolterman The first sentence reads: "In C# you don't need locks etc for this." I'm not saying anything about locks in general, I'm specifically refering to this application. – Dennis Traub Jul 16 '14 at 08:22
  • First off many many thanks for the answers and comments, I'm failry new to C# and lagging very far behind after spend years in VB classic and a few dunks in JAVA. I understand that my use of a secondary reference is acceptable it just felt wrong and is actually what prompted my question. I surely wasn't expecting anyone to rewrite my code snippets and the example Dennis Traub did is what I find most comfortable to work with at my stage of development, and really clarified using a singleton for me without subverting it to a global. Understand about the use of case. Again thanks. – Kini Jul 16 '14 at 15:08
1

You need to ask the singleton for its reference to access the values, yes. You don't need to store that reference in a local variable if you don't want to, although you certainly can. If you don't want to you can access the value from the instance directly:

lblDataBase.Text = clsRegistry.GetInstance().dataBase;
Servy
  • 202,030
  • 26
  • 332
  • 449
  • uhm.. downvoter - please explain? I fail to see why this deserves a downvote – default Jul 15 '14 at 20:55
  • @Default The fact that I've explained why two of the other answers posted to this question aren't appropriate answers at the same time that those answers attracted a downvote might have something to do with it. – Servy Jul 15 '14 at 20:57
  • @Servy You can trust me to not downvote anyone to get back at them. So no, I don't know why you were downvoted. – Dennis Traub Jul 15 '14 at 20:58