Bonjour : j'aimerais contraindre qu'à la compilation, une constante ne soit appelé qu'une et une seul fois.
Est-ce quelque chose d'envisageable ?
Version imprimable
Bonjour : j'aimerais contraindre qu'à la compilation, une constante ne soit appelé qu'une et une seul fois.
Est-ce quelque chose d'envisageable ?
Bonjour,
Tu as quoi comme impératif pour vouloir une telle chose ?
Pourquoi pas un compteur ? Pourquoi qu'une seule fois ?
En tout cas je serais surpris que cela soit faisable ! mais qui sait :roll: !
J@ck.
Bonjour,
Il faut nous donner d’avantages d'éléments concernant ta problématique car cela me semble particulièrement bizarre de vouloir accéder à une constante une seule fois lors de la compilation ????? :aie:
Héhé :
Je m'attendais à ce genre de réponse.
Bon, il y a plusieurs cas ou ça me paraîtrais judicieux : certains sont directement lié à mon activité donc délicat, un autre à un défaut (ou de l'incompétence) lié à une librairie exotique utilisé...
Enfin, je vois un cas qui pourrais parler à tous :
Avoir un struct (ou un autre type) contenant une liste d'identifiant (typiquement du string ou du char[]) pour une appli web. Ces identifiants (réutilisé en javascript) doivent être unique dans l'ensemble de l'appli.
Les composants les utilisant peuvent se retrouver sur la même page de manière très aléatoire car l'utilisateur final compose son interface à sa convenance.
bref, ça peut donner des bugs difficile à reproduire.
L'idée était de prendre le mal à la source et éviter d'appeler l'identifiant plusieurs fois.
Une solution avec un test à l’exécution permettrait d'identifier le soucis mais après mise en prod donc bof.
Sinon, je sais qu'il est possible d'utiliser des identifiants uniques (uuid) ou d'utiliser une nomenclature de nommage (genre namespace) pour éviter la majorité des cas... mais tout ça me semble peut convainquant.
Ce qui me surprend, c'est que j'ai mis ça en place dans un autre langage (Rust : que j'utilise à titre perso pour étendre mes connaissances) sans difficulté particulière.
Il nous est difficile de comprendre ce que tu cherches a faire, tu expliques tres mal ton cas :aie:
Si je comprends bien, tu veux pouvoir disposer d'une liste d'identifiants sans doublons. C'est bien ca ?
Si oui, tu peux utiliser un HashSet ou un SortedSet si l'ordre est important, et si tu utilises .NET Framework >= 4.
Il y a aussi le type Dictionary qui permet de s'assurer qu'une cle (donc un identifiant dans ton cas) n'existe qu'une seule fois.
Si aucun de ces types ne correspond a ce que tu cherches, tu peux aussi implementer ta propre classe qui derive d'une liste et qui va controler qu'il n'y ait pas de doublon lorsqu'un element est ajoute.
Enfin, si cela ne correspond pas a ta recherche, explique-toi plus clairement et eventuellement poste un exemple concret.
C'est bien une liste d'identifiants sans doublons mais je veux faire ce test à la compilation.
Je connais les HashSet, SortedSet et les Dictionary et ça ne répond pas vraiment à la problématique.
Le s 3 pré-cités vont tester les doublons lors de l'ajout mais rien ne m'interdit d'appeler plusieurs fois la même clés à des endroits différents...
Si j'étais dans une problématique de test à l’exécution, je ferais sans doute quelque chose qui s'apparenterais à ça :
Seulement, j'aimerais faire çaCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 using System; using System.Collections.Generic; namespace test { public class Program { public class AppException : Exception { public AppException(String message) : base (message) {} public AppException(String message, Exception inner) : base(message,inner) {} } public class MonDic : Dictionary<int, string> { public string donne(int cle) { if (this.ContainsKey(cle)) { string valeur = this[cle]; this.Remove(cle); return valeur; } throw new AppException("Y'a un doublon d'id"); } } public static void Main(string[] args) { MonDic d = new MonDic(); d.Add(1, "un"); d.Add(2, "deux"); d.Add(3, "trois"); Console.WriteLine(d.donne(1)); Console.WriteLine(d.donne(1)); } } }
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 using System; namespace test { public class Program { public static class ListeID { public static string idRechercheComposantUn = "idUn"; // ... public static string idRechercheComposantMille = "idMille"; } public static void Main(string[] args) { // Dans l'appli Un Console.WriteLine(ListeID.idRechercheComposantUn); // Dans l'appli mille, le dev c'est paluché : il appelle l'id du composant mille // => ça marche dans ses tests car il n'a pas testé les 2 composants (Un et Mille) dans la même page ! Console.WriteLine(ListeID.idRechercheComposantUn); } } }
J'avoue que comme les autres je ne vois pas trop où tu veux en venir.
S'il s'agit d'avoir une constante pour faire un identifiant unique tu peux effectivement utiliser les guid. Tu peux en générer toi-même, tu as pour ça un outil dans visual studio : Outils / Créer un Guid. Sinon tu peux créer les Guid à la volée (Guid.NewGUid());
Je peux te proposer un bout pour faire un contrôle à l'exécution :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 public static class GuidVault { private static HashSet<Guid> _guidSet = new HashSet<Guid>(); public static Guid UseOnce(Guid guid) { if (!_guidSet.Add(guid)) throw new InvalidOperationException($"Guid [{guid}] is already in use"); return guid; } public static Guid UseOnce(string guid) { return UseOnce(Guid.Parse(guid)); } }
Utilisé comme ça :
Code:
1
2
3
4
5 public static void Main(string[] args) { var id1 = GuidVault.UseOnce(Guid.NewGuid()); var id2 = GuidVault.UseOnce("{175E42CE-AD43-49D4-8774-A2ADB872535F}"); }
Sinon peut-être qu'il te faut une approche différente et externaliser la génération des id ; par exemple en les créant / stockant dans une base de donnée, ce qui te donnera une persistance des id déjà utilisés entre les différentes exécutions de ton(es) application(s).
Mon objectif c'est de l'assurance qualité.
Pour ça, en général : y'a 2 moyens (d'automatiser) : ceux qu'on peut couvrir en architecturant bien son soft pour que ça ne compile pas quand il y a un oubli (ex : Une nouvelle classe n'implémente pas son interface) soit on fait du test unitaire.
J'essai toujours avant de passer à l'étape 2, de m'assurer qu'il n'y a pas une solution plus élégante.
Merci Noxen de ton intervention. J'ai précisé auparavant que la génération d'id me semblait peut convainquant car les ids bougent tout le temps (si j'écris des id générés en dur, j'en reviens au même soucis => comment m'assurer que le même id n'est pas appelé 2 fois sans le détecter à l’exécution : ça m'obligerais sans doute à un mixe des 2 : on utilise des ids générés en dur avec un test d'appel : si déjà appelé, on en génère un) et son pas "human readable" => pour débugger la partie cliente, ça devient vite un soucis.
Je réexplique le contexte :
1. J'utilise une appli web donc framework MVC.
2. Nous sommes plusieurs développeurs avec des compétences différentes et nivelées
2. Jusqu'à présent, nous déclarions nos id dans nos models
Soucis : les ids sont de type string : rien ne m'assure qu'un autre id comporte le même nom dans un autre model pour diverses raisons (oubli de suppression, mauvaise fusion de source, négligence etc.).
Du coup, l'idée était de tout centraliser dans un fichier et de faire de la vérif pre-compile via un petit script. Problème : rien n'empêche d'appeler 2 fois la même propriété et le script de pré-compile ne peut pas décemment parcourir l'ensemble de la solution.
Bon, à force de reposer le problème et d'y réfléchir, je pense avoir trouvé une solution (presque acceptable) :
J'utilise le pré-processeur :
// Dans mon global.asax
Dans mes Models : je vais utiliser la réflexion pour générer mon ID avec le namespace et le nom de mon model (qui eux sont uniques et testé à la compilation) comme préfixe.Code:
1
2
3
4
5
6 #if DEBUG bool genererID = false; # else bool genererID = true; #endif
C'est verbeux mais ça me parait le meilleur compromis.
Par contre, je n'en démore pas : il doit y a avoir un moyen de faire ce que je cherchais à l'origine : le compilateur fait forcément ce genre d'optimisation :
- un appel => accès directe à la ressource
- plusieurs appels => utilisation d'un pointeur
Ce sont des id de quoi ? De modèles ? De classe ? De données ? De composants ? De contrôleurs ? De vues ? Comment sont-ils utilisés ? Quelle unicité doivent-ils valider ?
J'en ai déjà parlé : c'est des ids qui identifie des zones html : donc réutilisé en javascript. L'unicité qu'il doit valider : éviter d'avoir 2 id dans la même page HTML et du coup éviter par exemple d'avoir des effets transverses à la noix : un composant qui envoi la requète ajax d'un autre composant.
(Bref, une problématique vielle comme le web)
Je savais que j'avais vu quelque chose sur le sujet mais je ne me souvenais plus où, j'ai fini par retrouver. Il est possible de préfixer les id de champs créés via les modèles d'affichage et les helpers (ex: Html.TextBoxFor(...)). Cela se fait en deux temps : on précise le préfixe dans le ViewData de l'action qui émet la vue, puis dans l'attribut Bind du paramètre de l'action qui doit récupérer des données de la vue. Exemple avec une classe ProductController :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 private const string LocalPrefix = "Product"; public ActionResult Create() { ViewData.TemplateInfo.HtmlFieldPrefix = LocalPrefix; return View(new Product()); } [HttpPost] public ActionResult Create([Bind(Prefix=LocalPrefix)] Product product) { ViewData.TemplateInfo.HtmlFieldPrefix = LocalPrefix; if(!ModelState.IsValid) return View(product); if(!productService.Create(product)){ ModelState.AddModelError("error", "Une erreur s'est produite"); return View(product); } return RedirectToAction("Read", "Product", new { id = product.Id }); }
Pour l'id du produit cela donnera un input avec comme id "Product_Id" et comme name "Product.Id".
À noter : puisque l'on passe par un attribut le préfixe doit être une valeur sérialisable et "compile time constant", c'est à dire une chaîne de caractères explicite ou une constante chaîne de caractères. Par ailleurs C#6 introduit le mot clé nameof qui permet de récupérer sous forme de chaîne de caractères le nom d'un objet (class, méthode, propriété ou variable). D'où par exemple cette notation :
Ou bien :Code:private const string LocalPrefix = nameof(Product);
Code:private const string LocalPrefix = $"{nameof(Create)}.{nameof(Product)}";
Merci de ta réponse Noxen et désolé pour ma réponse tardive.
En effet, je ne connaissais pas cette astuce avec localprefix : elle me sera sans doute utile pour d'autres choses. (Là, j'ai utilisé la réflexion pour avoir quelque chose de pleinement générique)
Pour ce qui est nameof : je connais et je l'utilise mais pas exactement comme dans ton exemple car il m'est impossible pour l'instant de passer à C sharp 6.