Se requiere un bloqueo con una inicialización diferida en un tipo profundamente inmutable?

Si tengo un tipo profundamente inmutable (todos los miembros son de solo lectura y si son miembros del tipo de referencia, también se refieren a objetos que son profundamente inmutables).

Me gustaría implementar una propiedad inicializada diferida en el tipo, como esta:

private ReadOnlyCollection<SomeImmutableType> m_PropName = null;
public ReadOnlyCollection<SomeImmutableType> PropName
{
    get
    {
        if(null == m_PropName)
        {
            ReadOnlyCollection<SomeImmutableType> temp = /* do lazy init */;
            m_PropName = temp;
        }
        return m_PropName;
    }
}

De lo que puedo decir:

m_PropName = temp; 

... es seguro. No estoy demasiado preocupado por dos subprocesos, ambos corriendo para inicializar al mismo tiempo, porque será raro, ambos resultados serían idénticos desde una perspectiva lógica, y prefiero no usar un candado si no tengo a

¿Esto funcionara? ¿Cuáles son los pros y los contras

Editar Gracias por tus respuestas. Probablemente avanzaré con el uso de un candado. Sin embargo, me sorprende que nadie haya planteado la posibilidad de que el compilador se dé cuenta de que la variable temporal es innecesaria y simplemente asigne directamente a m_PropName. Si ese fuera el caso, un hilo de lectura podría leer un objeto que no ha terminado de construirse. ¿El compilador previene tal situación?

(Las respuestas parecen indicar que el tiempo de ejecución no permitirá que esto suceda).

Editar Así que he decidido utilizar un método CompareExchange entrelazado inspirado eneste artículo de Joe Duffy.

Básicamente

private ReadOnlyCollection<SomeImmutableType> m_PropName = null;
public ReadOnlyCollection<SomeImmutableType> PropName
{
    get
    {
        if(null == m_PropName)
        {
            ReadOnlyCollection<SomeImmutableType> temp = /* do lazy init */;
            System.Threading.Interlocked(ref m_PropName, temp, null);
        }
        return m_PropName;
    }
}

Se supone que esto garantiza que todos los hilos que llaman a este método en esta instancia de objeto obtendrán una referencia al mismo objeto, por lo que el operador == funcionará. Es posible que haya desperdiciado el trabajo, lo cual está bien, solo lo convierte en un algoritmo optimista.

Como se señala en algunos comentarios a continuación, esto depende del modelo de memoria .NET 2.0 para funcionar. De lo contrario, m_PropName debería declararse volátil.

Respuestas a la pregunta(8)

Su respuesta a la pregunta