2017-02-24 3 views
2

J'ai une propriété dont getter devrait charger sa valeur seulement la première fois. La deuxième fois, il retourne la valeur chargée sans le charger à nouveau:Charger la propriété paresseux chargement

private Object _MemberValue; 

public Object MemberValue 
{ 
    get 
    { 
     if(_MemberValue == null) 
     { 
      _MemberValue = LoadMember(); 
     } 

     return _MemberValue; 
    } 
} 

En VB.NET il y a le mot-clé Static. Avec cela, vous n'avez pas besoin de déclarer un membre à l'échelle de la classe.

Public Property MemberValue as Object 
    Get 
     Static value as Object = Nothing 

     If (value is Nothing) Then 
      value = LoadMember() 
     End If 

     Return value 
    End Get 
End Property 

En C#, il n'y a pas un tel mot-clé.

Y a-t-il de meilleures implémentations C# de ce problème ou d'autres motifs?

+2

[Lecture recommandée pourquoi l'utilisation 'Static' est mauvais.] (Http://stackoverflow.com/a/7475348/993547) –

+0

Découvrez l'objet Lazy – Nkosi

+2

Quel est le problème avec votre premier extrait btw? –

Répondre

7

Y a-t-il de meilleures implémentations C# de ce problème ou d'autres motifs?

Probablement pas. Vous pouvez utiliser Lazy<T> comme un remplacement si vous le souhaitez, mais fondamentalement, il est le même que votre premier exemple. En utilisant Static dans VB.NET has some serious drawbacks, donc je ne l'utiliserais pas de toute façon.

Si vous préférez Lazy<T>, ce que je voudrais utiliser:

private Lazy<object> _MemberLazy = new Lazy<object>(LoadMember); 

public object MemberValue 
{ 
    get 
    { 
     return _MemberLazy.Value; 
    } 
} 
+3

Eh bien, je suppose que je méritais la downvote depuis que j'ai essayé de vous aider les gars avec votre malentendu de Static' de VB.NET .. –

+3

Quelqu'un abuse du système, a un upvote. –

+1

Quelqu'un a une journée sur cette question. Clairement n'aime pas la question ni les réponses. +1 de moi cependant. – Bugs

4

Votre approche initiale semble appropriée, je n'ai jamais eu de raison de faire quelque chose de différent. Cela dit si votre objectif ici est d'éviter un champ de niveau de classe qui pourrait potentiellement être écrit à l'extérieur du getter, peut-être quelque chose comme this fonctionnerait. Il existe un certain nombre d'autres implémentations ReadOnly, WriteOnce, SetOnce qui fonctionnent également de la même manière.

ReadOnlyField.cs

public class ReadOnlyField<T> 
{ 
    private bool _frozen; 
    private T _value; 

    public T Value 
    { 
     get { return _value; } 
     set 
     { 
      if (_frozen) 
       throw new InvalidOperationException(); 

      _value = value; 
     } 
    } 

    public void Freeze() 
    { 
     _frozen = true; 
    } 
} 

YourObject.cs

public class YourObject 
{ 
    private readonly ReadOnlyField<object> _someMember; 

    public object MemberValue 
    { 
     get 
     { 
      if(_someMember.Value == null) 
      { 
       _someMember.Value = LoadMember(); 
       _someMember.Freeze(); 
      } 

      return _someMember.Value; 
     } 
    } 

    public YourObject() 
    { 
     _someMember = new ReadOnlyField<object>(); 
    } 
} 

Ce n'est pas parfait. Contrairement à votre exemple VB.Net; Le code en dehors du getter peut d'abord écrire dans le champ, mais au moins vous êtes protégé contre l'écrasement après l'appel de Freeze.

+2

Je n'ai pas voté mais je suppose que c'est parce qu'il semble que vous reproduisez ce que fait Lazy , qui a commencé dans .NET 4 –

+0

@the_lotus Lazy a ses propres limites. La question n'est pas claire et n'est pas réaliste. La charge pourrait être une fonction d'autres variables et vous pourriez avoir besoin de rafraîchir de l'interface utilisateur ou d'autres événements .. –