具有可触发初始化的C#单例模式
我需要一个单身汉:具有可触发初始化的C#单例模式,c#,.net,singleton,initialization,C#,.net,Singleton,Initialization,我需要一个单身汉: 是惰性负载吗 线程安全吗 在构造时加载一些值 可以随时查询这些值 初始化可能在某个精确的时间发生,在查询开始之前-因此我必须能够以某种方式从外部触发它。当然,多次触发只能进行一次初始化 我使用.NET3.5 我从Jon Skeet的(第5版)开始使用静态子类: public sealed class Singleton { IEnumerable<string> Values {get; private set;} private Single
- 是惰性负载吗
- 线程安全吗
- 在构造时加载一些值
- 可以随时查询这些值
- 初始化可能在某个精确的时间发生,在查询开始之前-因此我必须能够以某种方式从外部触发它。当然,多次触发只能进行一次初始化
public sealed class Singleton
{
IEnumerable<string> Values {get; private set;}
private Singleton()
{
Values = new[]{"quick", "brown", "fox"};
}
public static Singleton Instance { get { return Nested.instance; } }
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
看起来你可以做到:
public sealed class Singleton
{
IEnumerable<string> Values {get; private set;}
private Singleton(bool loadDefaults)
{
if (loadDefaults)
Values = new[]{"quick", "brown", "fox"};
else
Values = new[]{"another", "set", "of", "values"};
}
public static Singleton Instance { get { return Nested.instance; } }
public static void Initialize() {
Nested.Initialize();
}
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton(true);
private static object instanceLock = new object();
private static bool isInitialized = false;
public static void Initialize() {
lock(instanceLock) {
if (!isInitialized) {
isInitialized = true;
instance = new Singleton(false);
}
}
}
}
}
公共密封类单例
{
IEnumerable值{get;private set;}
私有单例(bool-loadDefaults)
{
如果(加载默认值)
value=new[]{“quick”、“brown”、“fox”};
其他的
Values=new[]{“另一个”、“集合”、“of”、“值”};
}
公共静态单例实例{get{return Nested.Instance;}}
公共静态void Initialize(){
Nested.Initialize();
}
私有类嵌套
{
//显式静态构造函数告诉C#编译器
//不将类型标记为beforefieldinit
静态嵌套()
{
}
内部静态只读单例实例=新单例(true);
私有静态对象instanceLock=新对象();
私有静态布尔值初始化=false;
公共静态void Initialize(){
锁(instanceLock){
如果(!i初始化){
isInitialized=true;
实例=新单例(false);
}
}
}
}
}
或创建要更新的单个实例:
public sealed class Singleton
{
IEnumerable<string> Values {get; private set;}
private Singleton()
{
Values = new[]{"quick", "brown", "fox"};
}
public static Singleton Instance { get { return Nested.instance; } }
private static object instanceLock = new object();
private static bool isInitialized = false;
public static void Initialize() {
lock(instanceLock) {
if (!isInitialized) {
isInitialized = true;
Instance.Values = new[]{"another", "set", "of", "values"};
}
}
}
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
公共密封类单例
{
IEnumerable值{get;private set;}
私人单身人士()
{
value=new[]{“quick”、“brown”、“fox”};
}
公共静态单例实例{get{return Nested.Instance;}}
私有静态对象instanceLock=新对象();
私有静态布尔值初始化=false;
公共静态void Initialize(){
锁(instanceLock){
如果(!i初始化){
isInitialized=true;
value=new[]{“另一个”、“集合”、“of”、“值”};
}
}
}
私有类嵌套
{
//显式静态构造函数告诉C#编译器
//不将类型标记为beforefieldinit
静态嵌套()
{
}
内部静态只读单例实例=新单例();
}
}
第三种变体基于不可变注释和嵌套类注释的删除:
public sealed class Singleton
{
IEnumerable<string> Values {get; private set;}
private Singleton()
{
Values = new[]{"quick", "brown", "fox"};
}
private static Singleton instance;
private static object instanceLock = new object();
public static Singleton Instance {
get {
Initialize();
return instance;
}
}
public static void Initialize() {
if (instance == null) {
lock(instanceLock) {
if (instance == null)
instance = new Singleton();
}
}
}
}
公共密封类单例
{
IEnumerable值{get;private set;}
私人单身人士()
{
value=new[]{“quick”、“brown”、“fox”};
}
私有静态单例实例;
私有静态对象instanceLock=新对象();
公共静态单例实例{
得到{
初始化();
返回实例;
}
}
公共静态void Initialize(){
if(实例==null){
锁(instanceLock){
if(实例==null)
instance=newsingleton();
}
}
}
}
您可以设置一个可以从外部触发的初始化方法,如果您需要稍后进行初始化,但是如果每次触发的值不同,那么它就不能是静态的,这违反了单例模式
基于您的示例(没有变量),我假设您只是延迟初始化(例程而不是构造函数),但您的问题表明您需要不同的值,但是如果多个初始化发生在一起,它只初始化一次,所以我对此有点困惑
我不确定您是否需要单例实现,但如果没有关于Initialize()是否每次运行相同的代码或是否具有某种类型的变量性质的信息,则无法完全回答。您可以使用双重检查锁定模式。只需在Singleton类中添加以下代码:
public sealed class Singleton
{
..........................
private static object locker = new object();
private static bool initialized = false;
public static void Initialize() {
if (!initialized){
lock(locker) {
if (!initialized){
//write initialization logic here
initialized = true;
}
}
}
}
.......................
}
你可以这样做
public sealed class Singleton
{
IEnumerable<string> Values { get; set; }
private Singleton()
{
Console.WriteLine("-- Private Singleton constructor");
Values = new[] { "quick", "brown", "fox" };
}
public static Singleton Instance
{
get
{
Console.WriteLine("- Singleton Instance");
return Nested.instance;
}
}
public static void Initialize()
{
Console.WriteLine("- Singleton Initialize");
Nested.Initialize();
}
internal class Nested
{
private static object syncRoot = new object();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
Console.WriteLine("-- Static Nested constructor");
}
internal static readonly Singleton instance = new Singleton();
internal static void Initialize()
{
lock (syncRoot)
{
Console.WriteLine("-- Locked");
Console.WriteLine("--- Nested Initialize");
Console.WriteLine("-- Unlocked");
}
}
}
}
哪个输出
- Singleton Instance
-- Private Singleton constructor
-- Static Nested constructor
- Singleton Instance
-----
- Singleton Initialize
-- Locked
--- Nested Initialize
-- Unlocked
- Singleton Initialize
-- Locked
--- Nested Initialize
-- Unlocked
- Singleton Initialize
-- Locked
--- Nested Initialize
-- Unlocked
公共类单例,其中T:class,new()
{
私有静态T实例;
公共静态T实例
{
得到
{
if(实例==null)
{
抛出新异常(“singleton需要在使用前进行初始化”);
}
返回实例;
}
}
公共静态无效初始化(操作初始化操作)
{
锁(类型(单件))
{
if(实例!=null)
{
返回;
}
实例=新的T();
初始化操作(实例);
}
}
}
我的第一个想法是只使用一个分配给singleton实例的一次性变量,它(可能?)会触发初始化
static Main()
{
var unused = Singleton.Instance;
//this should initialize the singleton, unless the compiler optimizes it out.
//I wonder if the compiler is smart enough to see this call has side effects.
var vals = Singleton.Instance.Values;
}
。。。但是,通过副作用编程是我努力避免的事情,所以让我们把意图说得更清楚一点
public class Singleton {
public static void Initialize() {
//this accesses the static field of the inner class which triggers the private Singleton() ctor.
Instance._Initialize();
}
private void _Initialize()
{ //do nothing
}
[the rest as before]
}
因此,用法是:
static Main()
{
//still wondering if the compiler might optimize this call out
Singleton.Initialize();
var vals = Singleton.Instance.Values;
}
顺便说一句,这也会起作用:
static Main()
{
var vals = Singleton.Instance.Values;
}
撇开编译器优化不谈,我认为这可以解决所有的需求。
公共静态void Initialize(){Singleton instance=instance;}
问题出在哪里?您的需求之一是“多次触发应该只进行一次初始化”,但是你说Jon Skeet模式的缺点之一是初始化“不能发生多次”。你真正需要的是什么?与你的问题没有直接关系,但你绝对确定你需要一个单例,我很少使用它们,而不会造成比它们解决的问题多得多的问题。@vickirk曾参与过一个名为“GlobalInstance”的单例引用已知宇宙中所有其他事物的项目,我明白你的意思。然而,我确实倾向于认为这是(为数不多的
public class Singleton {
public static void Initialize() {
//this accesses the static field of the inner class which triggers the private Singleton() ctor.
Instance._Initialize();
}
private void _Initialize()
{ //do nothing
}
[the rest as before]
}
static Main()
{
//still wondering if the compiler might optimize this call out
Singleton.Initialize();
var vals = Singleton.Instance.Values;
}
static Main()
{
var vals = Singleton.Instance.Values;
}