Je veux changer mes nombreux si en une table de consultation.
J'ai des types et des méthodes. Je veux les jumeler.
if (propertyType == typeof(bool) || propertyType == typeof(bool?)) DoBool(propertyType); if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?)) DoDateTime(propertyType); if (propertyType == typeof(Guid) || propertyType == typeof(Guid?)) DoGuid(propertyType);
Je dois créer un Dictionary
? Ou quelle est la meilleure façon élégante de faire cela?
Pouvez-vous me suggérer par où commencer ou par où puis-je trouver la solution?
4 Réponses :
Vous pouvez créer un Dictionary
:
dict[propertyType](propertyType)
Et puis l'appeler comme ceci:
var dict = new Dictionary<Type, Action<Type>>() { {typeof(bool), DoBool}, {typeof(bool?), DoBool}, {typeof(DateTime), DoDateTime}, {typeof(Datetime?), DoDateTime}, {typeof(Guid), DoGuid}, {typeof(Guid?), DoGuid} };
Vous pouvez créer une méthode pour initialiser votre table de recherche avec le type spécifié, pour éviter de se répéter.
private void AddEntry<T>(Action<Type> action) where T : struct { _lookup[typeof(T)] = action; _lookup[typeof(Nullable<T>)] = action; } private void DoInt(Type type) { /* implementation */ } AddEntry<bool>(type => { /* implementation */ }); AddEntry<int>(DoInt);
alors vous pouvez définir la méthode pour initialiser le _dict
,
private readonly IDictionary<Type, Action<Type>> _lookup;
Merci Johnny, je mixe quand j'en ai trouvé et cela suffit pour démarrer ma propre solution.
Puisqu'il s'agit plus de contrôler le flux du code que de recherche pure, j'utiliserais probablement une approche orientée objet et placerais le code pour chaque "gestionnaire" dans des classes séparées (avec des éléments communs dans une classe de base).
Vous pouvez créer une interface commune comme
public interface ITypeHandler { void HandleType(Type type); }
... et mettre l'implémentation des gestionnaires dans un dictionnaire de type Dictionary
séparation des préoccupations, testabilité, etc.
(Notez que * Handler n'est pas un très bon nom, vous devrez créer un meilleur nom en fonction du scénario que vous couvrez.)
J'ai créé ma propre implémentation qui est un peu différente, mais j'ai utilisé la suggestion @DaggeJ, alors merci!
J'ai d'abord créé une classe de gestionnaire de base. Après cela, j'ai utilisé cette base sur différentes classes de types. Vous pouvez le voir ci-dessous.
public IQueryable<T> GetQuery() { var queryHandlerList = new List<QueryHandler<T>>() { new IntQuery<T>(//Properties), new DateTimeQuery<T>(//Properties), new StringQuery<T>(//Properties), new BoolQuery<T>(//Properties), new GuidQuery<T>(//Properties), new EnumQuery<T>(//Properties) }; } return query = queryHandlerList.FirstOrDefault(h => GetType<T>(h, property.PropertyType)).Handle(); private bool GetType<T>(QueryHandler<T> handler, Type type) where T: class { if (handler.Types.FirstOrDefault(t => t == type) == type || handler.Types.FirstOrDefault(t => t == type.BaseType) == type.BaseType) return true; return false; }
Classe descendante:
internal class GuidQuery<T> : QueryHandler<T> where T : class { public override Type[] Types => new Type[] { typeof(Guid), typeof(Guid?) }; public GuidQuery(//Properties) : base(//Properties) { } public override IQueryable<T> Handle() { // Implementation } }
Vous pouvez certainement créer un
Dictionary>
- qui ressemble à ce que vous attendez de ce que vous nous avez montré.@JonSkeet Merci, quand j'ai créé ce dictionnaire, comment puis-je l'utiliser à la place des déclarations if?
if (myDictionary.TryGetValue (myType, out var action)) action (myType);
: vérifie s'il existe uneaction
pour un type donné (myType code >) et si c'est le cas, exécutez l '
action
Si vous êtes sûr qu'il y aura toujours une entrée, vous pouvez simplement utiliser
dictionary [propertyType] .Invoke (propertyType)
. Sinon, vous voudrez utiliserTryGetValue
et appeler la valeur uniquement s'il y a une entrée. Étant donné que lepropertyType
est de toute façon la clé, vous pouvez utiliser unDictionary
et simplement enregistrer des actions qui passeront l'argument approprié si nécessaire, bien sûr. Il est difficile de savoir ce qui est le mieux sans voir ce que font vos méthodes.@JonSkeet Merci pour la réponse que vous m'avez beaucoup aidé.