How to make a generic singleton base class C#
The problem is your generic constraint where T : class, new()
. The new()
constraint requires a public, parameterless constructor on T. There is no way around this; you need to provide such a constructor in Permission Controller
.
Generic SingletonT
The problem with a generic singleton factory is that since it is generic you do not control the "singleton" type that is instantiated so you can never guarantee that the instance you create will be the only instance in the application.
If a user can provide a type to as a generic type argument then they can also create instances of that type. In other words, you cannot create a generic singleton factory - it undermines the pattern itself.
How to implement a singleton in C#?
If you are just storing some global values and have some methods that don't need state, you don't need singleton. Just make the class and its properties/methods static.
public static class GlobalSomething
{
public static int NumberOfSomething { get; set; }
public static string MangleString( string someValue )
{
}
}
Singleton is most useful when you have a normal class with state, but you only want one of them. The links that others have provided should be useful in exploring the Singleton pattern.
An obvious singleton implementation for .NET?
This is the canonical, thread safe, lazy Singleton pattern in C#:
public sealed class Singleton
{
Singleton(){}
public static Singleton Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested() {}
internal static readonly Singleton instance = new Singleton();
}
}
Difference between these two Singleton implementations
I definitely would go with your first implementation...
the second seems questionable to me... if you need/want a lazy implementation you could use Lazy<T>
for that - since it is part of the framework it feels much more comfortable..
BTW: There are even more ways to implement the Singleton pattern... here is an excellent article.
Using Singleton in C#
If your Instance
method is written correctly, then you should be able to call it again in Form2
and get a reference to the exact same object that was created in Form1
.
Implementing Non blocking thread safe singleton logging class
In the end I have managed to achieve a non-blocking, thread safe,singleton logging class with the use of a background worker. I am submitting my solution in case someone find it useful someday.
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Diagnostics;
using System.Web.Configuration;
/// <summary>
/// Summary description for LogMessage
/// </summary>
public class LogMessage
{
static ReaderWriterLock locker = new ReaderWriterLock();
private static string serviceDirectory = HttpContext.Current != null ?
AppDomain.CurrentDomain.BaseDirectory :
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
private static string fullpath = serviceDirectory + "\\ActivityLog.log";
private static readonly LogMessage instance = new LogMessage();
public static LogMessage Instance
{
get { return instance; }
}
public void SaveLogMessage(string userName, string message, string stackTrace, bool inOut)
{
bool EnableActivityLogging = false;
if (string.IsNullOrEmpty(WebConfigurationManager.AppSettings["EnableActivityLogging"]))
return;
EnableActivityLogging = Convert.ToBoolean(WebConfigurationManager.AppSettings["EnableActivityLogging"]);
if (!EnableActivityLogging)
return;
BackgroundWorker logbw = new BackgroundWorker();
logbw.DoWork += logbw_DoWork;
logbw.RunWorkerCompleted += logbw_RunWorkerCompleted;
List<string> paramList = new List<string>();
paramList.Add(userName);
paramList.Add(message);
paramList.Add(stackTrace);
paramList.Add(inOut.ToString());
if (!logbw.IsBusy)
{
logbw.RunWorkerAsync(paramList);
}
}
void logbw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Write("Log Message Background Worker is now free...");
}
void logbw_DoWork(object sender, DoWorkEventArgs e)
{
List<string> paramList = (List<string>)e.Argument;
string userName = paramList[0].ToString();
string message = paramList[1].ToString();
string stackTrace = paramList[2].ToString();
bool inOut = bool.Parse(paramList[3].ToString());
try
{
locker.AcquireWriterLock(int.MaxValue);
using (StreamWriter logWriter =
new StreamWriter(fullpath, true))
{
string logMessage = "";
if (!string.IsNullOrEmpty(stackTrace))
{
if (inOut)//IN
{
logMessage = string.Format("{0} U:{1} IN:{2} E:{3}", DateTime.Now.ToString(), userName, message, stackTrace);
}
else//OUT
{
logMessage = string.Format("{0} U:{1} OUT:{2} E:{3}", DateTime.Now.ToString(), userName, message, stackTrace);
}
}
else
{
if (inOut)//IN
{
logMessage = string.Format("{0} U:{1} IN:{2}", DateTime.Now.ToString(), userName, message);
}
else//OUT
{
logMessage = string.Format("{0} U:{1} OUT:{2}", DateTime.Now.ToString(), userName, message);
}
}
logWriter.WriteLine(logMessage);
}
}
finally
{
locker.ReleaseWriterLock();
}
}
}
Now I can use this singleton object like below to save a log entry
LogMessage.Instance.SaveLogMessage(Context.User.Identity.Name, "Custom Message" + " M:" + MethodInfo.GetCurrentMethod().Name + "@" + Path.GetFileName(Page.AppRelativeVirtualPath), "", true);
Related Topics
Using Propertyinfo to Find Out the Property Type
How to Copy a File While It Is Being Used by Another Process
C# 3.0 Generic Type Inference - Passing a Delegate as a Function Parameter
Simple Way to Copy or Clone a Datarow
Any Reason to Use Auto-Implemented Properties Over Manual Implemented Properties
Equivalence of "With...End With" in C#
Selenium Stops When Browser Is Manually Interrupted
Get List of Zero Reference Codes in Visual Studio
ASP.NET Webapi: How to Perform a Multipart Post with File Upload Using Webapi Httpclient
In C#, How to Instantiate a Passed Generic Type Inside a Method
Wait Some Seconds Without Blocking UI Execution
How to Run Multiple SQL Commands in a Single SQL Connection