Примечание: Это полное переписывание исходного ответа;однако рекомендация остается в силе.
Во-первых: убедитесь, что вы не работаете под отладчиком.Например, окно наблюдения может касаться ваших общедоступных статических свойств.Это одна из возможных причин, по которой второй пример может вести себя иначе, чем первый.Это может звучать глупо, но вы никогда не знаете.
В .NET 4 ваш второй пример работает, и я, честно говоря, ожидаю , что он будет работать и в .NET 2.Пока вы не коснетесь свойства Context.Log
или LogFactory.instance
случайно.Тем не менее, он выглядит ужасно хрупким.
Кроме того, строго говоря, тонкости beforefieldinit
, которые вы здесь пытаетесь использовать, могут укусить вас в многопоточном приложении: инициализация LogFactory
не требуетработать в том же потоке, что и установщик Context.Log[Object]
.Это означает, что при инициализации LogFactory.instance
в этот thread Context.LogObject
еще не нужно устанавливать, а в другом (такие синхронизации могут выполняться лениво).Так что не потокобезопасен.Вы можете попытаться исправить это, сделав Context.LogObject
volatile , таким образом, набор будет виден во всех потоках одновременно.Но кто знает, в какие другие условия гонки мы попадаем в следующие.
И после всех трюков у вас все еще остается довольно неинтуитивный результат:
Context.Log = value1; // OK
Context.Log = value2; // IGNORED
Вы ожидаетеВторой вызов сеттера для работы (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);
}
}
Здесь результат гарантирован и ленив (в соответствии с пятым синглтон-методом Джона Скита),И выглядит ИМХО намного чище.