Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何延迟属性内的静态初始化_C#_.net_Singleton_Factory - Fatal编程技术网

C# 如何延迟属性内的静态初始化

C# 如何延迟属性内的静态初始化,c#,.net,singleton,factory,C#,.net,Singleton,Factory,我创建了一个类,它是一个(依赖注入)工厂和一个(依赖注入)工厂的交叉。称之为“Mono工厂”,它可以工作,看起来是这样的: public static class Context { public static BaseLogger LogObject = null; public static BaseLogger Log { get { return LogFactory.instance; }

我创建了一个类,它是一个(依赖注入)工厂和一个(依赖注入)工厂的交叉。称之为“Mono工厂”,它可以工作,看起来是这样的:

public static class Context
{
    public static BaseLogger LogObject = null;

    public static BaseLogger Log
    {
        get
        {
            return LogFactory.instance;
        }
    }

    class LogFactory
    {
        static LogFactory() { }
        internal static readonly BaseLogger instance = LogObject ?? new BaseLogger(null, null, null);
    }
}

//USAGE EXAMPLE:
//Optional initialization, done once when the application launches...
Context.LogObject = new ConLogger();

//Example invocation used throughout the rest of code...
Context.Log.Write("hello", LogSeverity.Information);
public static class Context
{
    private static BaseLogger LogObject = null;

    public static BaseLogger Log
    {
        get
        {
            return LogFactory.instance;
        }
        set
        {
            LogObject = value;
        }
    }

    class LogFactory
    {
        static LogFactory() { }
        internal static readonly BaseLogger instance = LogObject ?? new BaseLogger(null, null, null);
    }
}
其想法是,mono工厂可以扩展到处理多个项目(例如,多个记录器)。但我本想让mono工厂看起来像这样:

public static class Context
{
    public static BaseLogger LogObject = null;

    public static BaseLogger Log
    {
        get
        {
            return LogFactory.instance;
        }
    }

    class LogFactory
    {
        static LogFactory() { }
        internal static readonly BaseLogger instance = LogObject ?? new BaseLogger(null, null, null);
    }
}

//USAGE EXAMPLE:
//Optional initialization, done once when the application launches...
Context.LogObject = new ConLogger();

//Example invocation used throughout the rest of code...
Context.Log.Write("hello", LogSeverity.Information);
public static class Context
{
    private static BaseLogger LogObject = null;

    public static BaseLogger Log
    {
        get
        {
            return LogFactory.instance;
        }
        set
        {
            LogObject = value;
        }
    }

    class LogFactory
    {
        static LogFactory() { }
        internal static readonly BaseLogger instance = LogObject ?? new BaseLogger(null, null, null);
    }
}
上面的方法不起作用,因为当触及Log属性时(通过setter调用),它会导致执行与getter相关的代码路径……这意味着内部LogFactory“实例”数据总是被设置为BaseLogger(设置“LogObject”总是太晚了!)

那么,在调用设置的路径时,是否有一种装饰或其他技巧会导致Log属性的“get”路径变慢?

一些提示:

退房

我避免使用静态初始化。这在实践中可能会导致奇怪的问题。例如,如果您正在构建的内容抛出错误,那么windows加载程序将告诉您有问题,但不会告诉您问题所在。您的代码从未被实际调用,因此您没有机会出现异常来处理问题。我在第一次使用时构造第一个实例。下面是一个例子:

    private static OrderCompletion instance;

    /// <summary>
    /// Get the single instance of the object
    /// </summary>
    public static OrderCompletion Instance
    {
        get
        {
            lock (typeof(OrderCompletion))
            {
                if (instance == null)
                    instance = new OrderCompletion();
            }
            return instance;
        }
    }
私有静态OrderCompletion实例;
/// 
///获取对象的单个实例
/// 
公共静态OrderCompletion实例
{
得到
{
锁(类型(订单完成))
{
if(实例==null)
实例=新订单完成();
}
返回实例;
}
}
一些提示:

退房

我避免使用静态初始化。这在实践中可能会导致奇怪的问题。例如,如果您正在构建的内容抛出错误,那么windows加载程序将告诉您有问题,但不会告诉您问题所在。您的代码从未被实际调用,因此您没有机会出现异常来处理问题。我在第一次使用时构造第一个实例。下面是一个例子:

    private static OrderCompletion instance;

    /// <summary>
    /// Get the single instance of the object
    /// </summary>
    public static OrderCompletion Instance
    {
        get
        {
            lock (typeof(OrderCompletion))
            {
                if (instance == null)
                    instance = new OrderCompletion();
            }
            return instance;
        }
    }
私有静态OrderCompletion实例;
/// 
///获取对象的单个实例
/// 
公共静态OrderCompletion实例
{
得到
{
锁(类型(订单完成))
{
if(实例==null)
实例=新订单完成();
}
返回实例;
}
}

注意:这是对原始答案的完全重写;然而,这项建议仍然有效

第一:确保您没有在调试器下运行。例如,手表窗口可能会触及您的公共静态属性。这可能是第二个示例与第一个示例行为不同的原因之一。这听起来可能很傻,但你永远不知道

在.NET4下,您的第二个示例确实有效,我真诚地希望它在.NET2下也有效。只要不无意中触摸
Context.Log
属性或
LogFactory.instance
字段。然而,它看起来非常脆弱

此外,严格地说,您试图在这里使用的
beforefieldinit
微妙之处可能会在多线程应用程序中影响您:
LogFactory
的init不需要与
Context.Log[Object]
的setter运行在同一线程上。这意味着当初始化
LogFactory.instance
时,该线程上的
Context.LogObject
还不需要设置,而另一个线程上的
LogObject(此类同步可以延迟进行)。所以它不是线程安全的。您可以尝试通过使
Context.LogObject
易失性来修复此问题,这样可以一次在所有线程上看到集合。但谁知道下一步我们会遇到什么样的比赛条件呢

在所有这些技巧之后,您仍然会得到以下相当不直观的结果:

Context.Log = value1; // OK
Context.Log = value2; // IGNORED
您希望setter的第二次调用可以工作(
Context.Log==value2
)或抛出。不要被默默忽视

你也可以去

public static class Context
{
    private static BaseLogger LogObject;

    public static BaseLogger Log
    {
        get { return LogObject ?? LogFactory.instance; }
        set { LogObject = value; }
    }

    private class LogFactory
    {
        static LogFactory() {}
        internal static readonly BaseLogger instance 
               = new BaseLogger(null, null, null);
    }
}

在这里,结果是有保证的,并且是懒惰的(与Jon Skeet的第五个单例方法一致)。而且它看起来更干净了。注意:

这是对原始答案的完全重写;然而,这项建议仍然有效

第一:确保您没有在调试器下运行。例如,手表窗口可能会触及您的公共静态属性。这可能是第二个示例与第一个示例行为不同的原因之一。这听起来可能很傻,但你永远不知道

在.NET4下,您的第二个示例确实有效,我真诚地希望它在.NET2下也有效。只要不无意中触摸
Context.Log
属性或
LogFactory.instance
字段。然而,它看起来非常脆弱

此外,严格地说,您试图在这里使用的
beforefieldinit
微妙之处可能会在多线程应用程序中影响您:
LogFactory
的init不需要与
Context.Log[Object]
的setter运行在同一线程上。这意味着当初始化
LogFactory.instance
时,该线程上的
Context.LogObject
还不需要设置,而另一个线程上的
LogObject(此类同步可以延迟进行)。所以它不是线程安全的。您可以尝试通过使
Context.LogObject
易失性来修复此问题,这样可以一次在所有线程上看到集合。但谁知道下一步我们会遇到什么样的比赛条件呢

在所有这些技巧之后,您仍然会得到以下相当不直观的结果:

Context.Log = value1; // OK
Context.Log = value2; // IGNORED
您希望setter的第二次调用可以工作(
Context.Log==value2
)或抛出。不要被默默忽视

你也可以去

public static class Context
{
    private static BaseLogger LogObject;

    public static BaseLogger Log
    {
        get { return LogObject ?? LogFactory.instance; }
        set { LogObject = value; }
    }

    private class LogFactory
    {
        static LogFactory() {}
        internal static readonly BaseLogger instance 
               = new BaseLogger(null, null, null);
    }
}
在这里,结果是有保证的,而且是懒惰的(与Jon Skeet的第五种单例冰毒一致)