Question

Je me trouve souvent en train d'écrire une propriété qui est évaluée paresseusement. Quelque chose comme:

if (backingField == null) 
  backingField = SomeOperation();
return backingField;

Ce n'est pas beaucoup de code, mais il est souvent répété si vous avez beaucoup de propriétés.

Je songe à définir une classe appelée LazyProperty:

public class LazyProperty<T>
    {
    private readonly Func<T> getter;

    public LazyProperty(Func<T> getter)
    {
        this.getter = getter;
    }

    private bool loaded = false;
    private T propertyValue;

    public T Value
    {
        get
        {
            if (!loaded)
            {
                propertyValue = getter();
                loaded = true;
            }
            return propertyValue;
        }
    }

    public static implicit operator T(LazyProperty<T> rhs)
    {
        return rhs.Value;
    }
}

Cela me permettrait d’initialiser un champ comme celui-ci:

first = new LazyProperty<HeavyObject>(() => new HeavyObject { MyProperty = Value });

Ensuite, le corps de la propriété pourrait être réduit à:

public HeavyObject First { get { return first; } }

Cela serait utilisé par la plupart des entreprises, car cela irait dans une bibliothèque de classes commune partagée par la plupart de nos produits.

Je ne peux pas décider si c'est une bonne idée ou non. Je pense que la solution a quelques avantages, comme:

  • Moins de code
  • Code plus joli

Par contre, il serait plus difficile d’examiner le code et de déterminer exactement ce qui se passe - notamment si un développeur ne connaît pas la classe LazyProperty.

Qu'en penses-tu? Est-ce une bonne idée ou devrais-je l'abandonner? De même, l'opérateur implicite est-il une bonne idée ou préférez-vous utiliser explicitement la propriété Value si vous utilisez cette classe?

Les opinions et suggestions sont les bienvenues: -)

Était-ce utile?

La solution

Juste pour être trop pédant:

Votre solution proposée pour éviter de répéter le code:

private LazyProperty<HeavyObject> first = 
  new LazyProperty<HeavyObject>(() => new HeavyObject { MyProperty = Value });
public HeavyObject First { 
  get { 
    return first; 
  } 
}

Contient plus de caractères que le code que vous ne vouliez pas répéter:

private HeavyObject first;
public HeavyObject First { 
  get {
    if (first == null) first = new HeavyObject { MyProperty = Value };
    return first;
  }
}

À part cela, je pense que la distribution implicite a rendu le code très difficile à comprendre. Je n'aurais pas deviné qu'une méthode qui retourne simplement en premier finit par créer un HeavyObject. J'aurais au moins abandonné la conversion implicite et renvoyé en premier. Valeur de la propriété.

Autres conseils

Ne le faites pas du tout.

En règle générale, l’utilisation de ce type de propriétés initialisées différées est un choix de conception valide dans un cas: lorsque SomeOperation (); est une opération coûteuse (en termes d’E / S, comme lorsqu’il nécessite un DB ET, lorsque vous êtes certain de ne PAS souvent avoir besoin d’y accéder.

Cela dit, par défaut, vous devriez opter pour une initialisation rapide, et lorsque le profileur dit que c'est votre goulot d'étranglement, modifiez-le en initialisation différée.

Si vous avez envie de créer ce genre d'abstraction, c'est une odeur.

Vous voudriez sûrement au moins que le LazyPropery < T > soit un type de valeur, sinon vous avez ajouté de la mémoire et une pression GC pour chaque "chargé paresseux". propriété de votre système.

Aussi, qu'en est-il des scénarios à plusieurs threads? Considérons deux threads demandant la propriété en même temps. Sans verrouillage, vous pouvez potentiellement créer deux instances de la propriété sous-jacente. Pour éviter le verrouillage dans le cas habituel, vous souhaitez effectuer un verrouillage à double vérification.

Je préfère le premier code, car a) c'est un modèle si commun avec des propriétés que je le comprends tout de suite, et b) le point que vous avez soulevé: qu'il n'y a pas de magie cachée qui vous oblige à rechercher pour savoir où et lorsque la valeur est obtenue.

J'aime l’idée qu’il est beaucoup moins codé et plus élégant, mais je serais très inquiet du fait qu’il devient difficile de le regarder et de dire ce qui se passe. La seule façon, à mon avis, d’avoir recours à cette méthode consiste à définir une convention pour les variables définies à l’aide du paramètre "lazy". façon, et aussi de commenter partout où il est utilisé. Maintenant, il ne va pas y avoir de compilateur ou quoi que ce soit qui va appliquer ces règles, donc toujours YMMV.

En fin de compte, pour moi, les décisions comme celle-ci se résument à qui va le regarder et à la qualité de ces programmeurs. Si vous pouvez faire confiance à vos collègues développeurs pour l'utiliser correctement et commenter correctement, allez-y, mais sinon, vous feriez mieux de le faire d'une manière facile à comprendre et à suivre. / mes 2cents

Je ne pense pas que l'inquiétude d'un développeur qui ne comprend pas soit un bon argument contre une telle chose.

Si vous pensez que vous ne pouvez rien faire alors que vous craignez que quelqu'un ne comprenne pas ce que vous avez fait

Vous pouvez écrire un tutoriel ou quelque chose dans un référentiel central, nous avons ici un wiki pour ce genre de notes

Dans l’ensemble, je pense que c’est une bonne idée de mise en œuvre (ne pas vouloir lancer un débat, que le chargement par lazy soit une bonne idée ou non)

Dans ce cas, je crée un Extrait de code Visual Studio . Je pense que c'est ce que vous devriez vraiment faire.

Par exemple, lorsque je crée des contrôles ASP.NET, les données stockées dans ViewState sont souvent très fréquentes. J'ai donc créé un extrait de code comme celui-ci:

public Type Value
{
    get
    {
        if(ViewState["key"] == null)
            ViewState["key"] = someDefaultValue;
        return (Type)ViewState["key"];
    }
    set{ ViewState["key"] = value; }
}

De cette façon, le code peut être facilement créé avec seulement un peu de travail (définition du type, de la clé, du nom et de la valeur par défaut). C'est réutilisable, mais vous n'avez pas l'inconvénient d'un morceau de code complexe que d'autres développeurs pourraient ne pas comprendre.

J'aime votre solution car elle est très intelligente, mais je ne pense pas que vous gagniez beaucoup en l’utilisant. Le chargement paresseux d'un champ privé dans une propriété publique est certainement un endroit où le code peut être dupliqué. Cependant, cela m’a toujours paru comme un modèle à utiliser plutôt que du code qui doit être refondu dans un lieu commun.

Si vous effectuez une sérialisation, votre approche risque de poser problème à l'avenir. De plus, il est plus compliqué au départ de comprendre ce que vous faites avec le type personnalisé.

Dans l’ensemble, j’applaudis à votre tentative et apprécie son intelligence, mais je vous suggérerais de revenir à votre solution initiale pour les raisons indiquées ci-dessus.

Personnellement, je ne pense pas que la classe LazyProperty offre suffisamment de valeur pour justifier son utilisation, surtout si l’on considère les inconvénients de l’utiliser pour les types valeur (comme l'a mentionné Kent). Si vous aviez besoin d’autres fonctionnalités (comme le rendre multithread), il pourrait être justifié d’être une classe ThreadSafeLazyProperty.

En ce qui concerne la propriété implicite, j'aime bien la "Valeur". la propriété mieux. C'est un peu plus de frappe, mais beaucoup plus clair pour moi.

Je pense que c'est une idée intéressante. Premièrement, je vous recommanderais de masquer la propriété Lazy du code d'appel. Vous ne voulez pas laisser filtrer dans votre modèle de domaine le fait qu'il soit paresseux. Ce que vous faites avec l'opérateur implicite, alors gardez-le.

J'aime la façon dont vous pouvez utiliser cette approche pour gérer et résumer les détails du verrouillage, par exemple. Si vous faites cela, alors je pense qu'il y a de la valeur et du mérite. Si vous ajoutez le verrouillage, surveillez le motif de double verrouillage, il est très facile de se tromper.

Vous pouvez utiliser les itérateurs C #. Le post suivant explique un exemple d’utilisation et les avantages de son utilisation.

http://hemanshubhojak.com/Home/Post?postId=3

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top