Pergunta

Eu tenho esse objeto de cache Singleton e expõe uma propriedade IEnumerable que apenas retorna uma variável IEnumerable privado.

Eu tenho um método estático no meu objeto singleton que as atualizações dessa variável de membro (que existe na instância single 'Instância' deste objeto cache).

Vamos dizer alguma linha está interagindo sobre este IEnumerable variável / propriedade, enquanto o cache é atualizado. Eu fiz isso para que o cache está atualizando sobre uma nova variável local e, finalmente, definir a variável privada exposta a pontos a esta nova variável local.

Eu sei que eu só estou atualizando uma referência, deixando o objeto outro (velho) na espera de memória para ser captado pelo GC, mas o meu problema é - eu não estou 100% de certeza o que acontece quando eu definir a nova referência ? Será que o outro segmento de repente ser iteração sobre o novo objeto ou o velho que passou com a interface IEnumerable? Se tivesse sido uma referência normal, eu diria 'não'. O segmento de chamada seria a operar no objeto de idade, mas não tenho certeza se este é o caso de IEnumerable também?

Aqui é a classe despojado:

internal sealed class SektionCache : CacheBase
{
    public static readonly SektionCache Instance = new SektionCache();
    private static readonly object lockObject = new object();
    private static bool isUpdating;

    private IEnumerable<Sektion> sektioner;

    static SektionCache()
    {
        UpdateCache();
    }

    public IEnumerable<Sektion> Sektioner
    {
        get { return sektioner; }
    }

    public static void UpdateCache()
    {
    // SNIP - getting data, locking etc.
    Instance.sektioner = newSektioner;
    // SNIP
    }
}
Foi útil?

Solução

A discussão que está enumerando sektioner vai continuar a enumerá-lo mesmo quando você atualizar a referência dentro do Singleton. Não há nada de especial sobre os objetos que implementam IEnumerable.

Você deve talvez adicionar o volátil palavra-chave para o campo sektioner como você não está fornecendo leitura de bloqueio e vários segmentos estão lendo / escrevendo.

Outras dicas

Uma vez que o { return sektioner; } getter é chamado antes o novo valor é colocado no campo, o valor antigo é retornado. Em seguida, o foreach (Sektion s in cache.Sektioner) circuito usa o valor que foi recebido quando o getter foi chamado, ou seja, o valor antigo. Esse valor será usado em todo o loop foreach.

Primeiro de tudo eu não posso ver bloqueio objeto, variável LockObject não utilizado me deixa triste. IEnumerable não é especial. Cada segmento terá a sua própria cópia de referência a alguma instância de objeto sektioner. Você não pode afetar outros segmentos dessa maneira. O que aconteceria com a versão antiga dos dados apontados pelo campo sektioner depende em grande medida chamando partido.

Eu acho que, se você quiser um segurança do thread, você deve usar desta forma:

internal sealed class SektionCache : CacheBase
{
    //public static readonly SektionCache Instance = new SektionCache();

    // this template is better ( safer ) than the previous one, for thread-safe singleton patter >>>
    private static SektionCache defaultInstance;
    private static object readonly lockObject = new object();
    public static SektionCach Default {
        get {
            SektionCach result = defaultInstance;
            if ( null == result ) {
                lock( lockObject ) {
                    if ( null == result ) {
                        defaultInstance = result = new SektionCache();
                    }
                }
            }

            return result;
        }
    }
    // <<< this template is better ( safer ) than the previous one

    //private static readonly object lockObject = new object();
    //private static bool isUpdating;
    //private IEnumerable<Sektion> sektioner;

    // this declaration is enough
    private volatile IEnumerable<Sektion> sektioner;

    // no static constructor is required >>>
    //static SektionCache()
    //{
    //    UpdateCache();
    //}
    // <<< no static constructor is required

    // I think, you can use getter and setter for reading & changing a collection
    public IEnumerable<Sektion> Sektioner {
        get {
            IEnumerable<Sektion> result = this.sektioner;
            // i don't know, if you need this functionality >>>
            // if ( null == result ) { result = new Sektion[0]; }
            // <<< i don't know, if you need this functionality
            return result;
        }
        set { this.sektion = value; }
    }

    //public static void UpdateCache()
    //{
    //// SNIP - getting data, locking etc.
    //Instance.sektioner = newSektioner;
    //// SNIP
    //}
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top