-1
votes

Comment implémenter un régleur d'initialisation automatique en C #

Je veux utiliser des informations qui se cachent avec un accessoir d'une propriété. Donc, je veux déclencher l'accesseur de set sans mettre de valeur. Dans l'ensemble Acessor est l'initialisation de la valeur, comme celle-ci: xxx

question : pourquoi je veux faire cela? réponse : deux raisons: 1. Je souhaite également réinitialiser cela, j'utilise une liste mise en cache d'une table avec des lignes de base de données. Lorsque cette table est mise à jour, je souhaite actualiser la liste mise en cache. Je ne veux pas utiliser des setters lisibles difficiles pour cela et veulent donc masquer l'initialisation de l'installation. 2. I Utilisez les noms de clés, les erreurs de frappe sont alors possibles, gardez ces noms ensemble est une excellente solution. Qu'est-ce qui fonctionne? Possible pas si grande solution: shortrefcontrols = null

est la langue C # manquante quelque chose? ou suis-je (MIS) en utilisant des propriétés de cette façon. shortrefcontrols = null fonctionne, mais si une autre collègue de mienne maintient ce code, il pourrait obtenir l'impression que la valeur de ShortrefControls est définie sur NULL.

La meilleure solution que je puisse arriver, c'est de N'utilisez pas de propriétés pour cela et utilisez une fonction distincte getShortrefControls () et SeShortrefControls () ().

Mise à jour : i (ahum ... mon collègue ;-) est venu Ceci: xxx

Cette fonction privée est utilisée comme valeur de réglage. D'une certaine manière, son comportement comme un alias ou une enveloppe pour le setter. ce qui ne va pas avec cela? sa fonction supplémentaire qui ne serait pas vraiment nécessaire.

c # version x? est-il étrange de penser que est étrange Shortrefcontrols = << / Code> est l'initialisation sans valeur, est un moyen de gérer cela dans une future version de C #. Les caractères = << / forts> pourraient être hors du parcours des caractères, ce qui signifie une initialisation automatique. Pour laisser le setter se comporter comme un setter devrait, le = dit que les shortrefcontrols devraient avoir une valeur, le << / fort> dit qu'il sera initialisé par lui-même et non passé comme valeur.

Mise à jour 2 : Eh bien après la pensée supplémentaire, je suis venu avec ceci: xxx

i postfixed la méthodname avec la liste donc nous savons un La liste est référencée pour plus de clarté. Ce n'est pas ce que je veux vraiment et pas efficace non plus parce qu'il renvoie toujours la valeur, donc je vois le code ci-dessus comme solution de contournement.

Ce que j'ai essayé et n'a pas fonctionné: shortrefcontrols = autocensialisation. Cela peut être une bonne solution. La soi-même est une variable de valeur null. Cela indique clairement ce que le sens sera. Un problème avec ceci est, je n'ai pas seulement les shortrefcontrols dans le tamisictionnaire, mais beaucoup plus de données avec différents types afin que cela ne fasse pas l'affaire.

Ce que je veux vraiment, c'est: Un setter auto-initialisation

Il y a donc une meilleure alternative pour gérer cela ou un bon conseil à l'équipe Visual Studio pour prolonger la langue?


3 commentaires

Tout le point de fabrication d'un setter est, de sorte que la valeur puisse être définie par des accesseurs de la propriété / code appelant le setter. Si vous voulez qu'un réglage soit «auto-initialisation», il défait tout le but d'un seigteur. Je ne vois pas la motivation pour "aller et initialiser une propriété" lorsqu'un appelant tente de définir sa valeur. Si vous souhaitez que la propriété ait une valeur par défaut, il suffit de la définir dans le constructeur ou de l'initialiser dans le getter.


Le problème est de ne pas initialiser, mais comment réinitialiser.


Je suis d'accord avec @Lennart, ce que vous essayez de faire violer le principe de responsabilité unique, qui (dans ce cas, une propriété) consiste à donner accès à un domaine dans le monde extérieur, qui ne se maintient pas "à jour" ( Peut-être que vous pouvez implémenter une collection personnalisée avec un Actualiser (ou quelque chose d'autre) et l'appelez comme obj.shortrefcontrols.refresh () quand vous avez besoin?)


3 Réponses :


3
votes

Vous avez raison que la langue ne prend pas en charge la syntaxe pour initialiser un setter.

À mon avis, le code que vous avez montré ne reflète pas vos choix de conception. Cela signifie que vous recherchez une syntaxe qui exprime votre intention mieux.

à mon avis, le shortrefcontrols doit être une propriété lisonly: xxx

Note latérale: Vous pouvez raccourcir cela sur ce qui suit: xxx

Suivant, sur pour mettre à jour le cache du Tabledictionner . Cela ne devrait pas être fait dans un établissement de propriétés: la valeur n'est pas utilisée, ce n'est donc pas paramètre la propriété, il fait autre chose. Les appelants seraient confus, car ce code ne fait pas ce qu'il semble faire: xxx

null est ignoré, mais shortrefcontrols est défini sur une autre valeur . Cela surprendrait la plupart des développeurs en regardant le code.

La méthode SeShortrefControls fait ce que vous devez mettre à jour l'entrée du dictionnaire. La question importante est quand devrait être invoquée. À partir des fragments de code, il est difficile de dire, mais voici quelques possibilités:

  1. Dans le cadre du Obtenir accessor pour shortrefcontrols . Cela garantirait que le dictionnaire est toujours à jour. Mais cela fait effectivement la tenue de la valeur mise en cache inutile.
  2. En réponse à une autre méthode (ou méthodes) qui invalide le cache. Je ne peux pas dire ce que ce viendraient de l'extrait prévu.
  3. après une certaine période de temps. Encore une fois, sans plus de contexte, je ne peux pas dire quelle période serait correcte.

1 commentaires

C'est pourquoi j'ai demandé s'il est possible d'étendre la langue C # avec un régleur d'initialisation automatique, aucune valeur n'est nécessaire. Le setter a une variable de champ interne, c'est sous la capuche une méthode définie. Je veux mettre cette variable. Le but de la conception est de tout maintenir avec un code minimal, mais gardez-le lisible.



1
votes

Vous pouvez initialiser le cache dans le constructeur et ne pas utiliser un setter. Ensuite, en fonction de vos conditions prédéfinies (dépenser) Getter May Recharger du cache. Vous pouvez faire une méthode de rechargement privée / publique selon que vous souhaitez donner aux utilisateurs de cette capacité de classe de recharger le cache explicitement.

public class TestClass
{
    private Dictionary<string, List<ShortRef_Control>> tableDictionary;

    public TestClass()
    {
        ReloadCache();
    }

    public List<ShortRef_Control> ShortRefControls
    {
        get
        {
            if (ShouldReload())
            {
                ReloadCache();
            }
            return tableDictionary["refcontrols"];
        }
    }

    public void ReloadCache()
    {
        tableDictionary["refcontrols"] =
           (from src in dataContext.ShortRef_Controls select src).ToList();
    }

    private bool ShouldReload()
    {
        return tableDictionary["refcontrols"] == null || !tableDictionary["refcontrols"].Any();
    }

}


2 commentaires

Le problème avec cette solution est de beaucoup de code est nécessaire. Le tablesdictionner est non seulement utilisé pour les shortrefcontrols, mais pour dire 10 autres requêtes relatives aux tables. Je veux mettre le contenu du tamisictionnel sur les comboboxes. Je veux aussi garder le code fermer / propre que possible. Si vous regardez votre code exemple, vous voyez la touche "REFCONTROLS" en trois parties de code distinctes. Je préfère garder ceux-ci dans une propriété Getter & Setter Combo. Pour l'instant, la langue C # ne supporte pas la situation d'un setter auto-initial, mais peut-être si suffisamment de personnes votent pour cela viennent :-)


Si elle utilisée ailleurs, vous pouvez déplacer la fonctionnalité de rechargement en dehors de cette classe (faire le dictionnaire statique) et mettre dans une classe d'assistance, de sorte qu'elle sera rechargée en un seul point, qui utilise ce cache fera référence au même dictionnaire. Les configurateurs sont déclenchés lorsque vous définissez une propriété, votre «Set d'initialisation» est ambiguë. Si vous souhaitez déclencher le chargement lorsque vous accédez à la première propriété (chargement paresseux) ou conditionnellement, vous devez utiliser Getter comme indiqué dans l'échantillon de code ci-dessus. L'utilisation de Setter à cette fin n'est pas la bonne façon.



0
votes

Que diriez-vous de développer la solution d'Ozanmut et d'utiliser un indexeur pour spécifier les noms de table?

Cela conserverait le modèle propre d'Ozanmut et il devrait également répondre à vos préoccupations avec la manipulation de plusieurs tables: P>

    public class Tables
    {
        private readonly IDictionary<string, List<ShortRef_Control>> tableDictionary = new Dictionary<string, List<ShortRef_Control>>();

        public List<ShortRef_Control> this[string tableName]
        {
            get
            {
                if (ShouldReload(tableName))
                    Reload(tableName);

                return tableDictionary[tableName];
            }
        }

        public void Reload()
        {
            foreach (var tableName in tableDictionary.Keys)
                Reload(tableName);
        }

        private void Reload(string tableName)
        {
            // implement table-specific loading logic here:
            switch (tableName)
            {
                case "refcontrols":
                {
                    tableDictionary[tableName] = (from src in dataContext.ShortRef_Controls select src).ToList();
                    break;
                }
                default:
                {
                    throw new NotSupportedException($"invalid table name: {tableName}");
                }
            }

            // note: in the real world I wouldn't use a switch statement to implement the logic, but this is just to 
            // illustrate the general concept
        }

        private bool ShouldReload(string tableName)
        {
            return tableDictionary[tableName] == null || !tableDictionary[tableName].Any();
        }
    }


    public class TestClass
    {
        private readonly Tables tables = new Tables();

        public TestClass()
        {
            tables.Reload();
        }

        // this indexer will allow you to access your various tables from outside this class by specifying the table name
        public List<ShortRef_Control> this[string name]
        {
            get { return tables[name]; }
        }

        // if you need your table names hard-coded, you can create separate properties for each one:
        public List<ShortRef_Control> RefControlsTable { get { return this["refcontrols"]; }}

        // here's a few examples of how the tables would be accessed or used

        public void UseTableRefControl()
        {
            UseTableRefControl(DoSomethingWithRecord);
        }

        public void UseTableRefControl(Action<ShortRef_Control> action)
        {
            TakeActionOnTable("refcontrols", DoSomethingWithRecord);
        }

        public void TakeActionOnTable(string tableName, Action<ShortRef_Control> action)
        {
            foreach (var row in tables[tableName])
                action(row);
        }

        private static void DoSomethingWithRecord(ShortRef_Control row)
        {
            // do something with the row here
        }
    }


0 commentaires