2
votes

Table de recherche en C # avec types et actions

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?


5 commentaires

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 une action pour un type donné ( myType ) 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 utiliser TryGetValue et appeler la valeur uniquement s'il y a une entrée. Étant donné que le propertyType est de toute façon la clé, vous pouvez utiliser un Dictionary 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é.


4 Réponses :


0
votes

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}
};


0 commentaires

0
votes

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;


1 commentaires

Merci Johnny, je mixe quand j'en ai trouvé et cela suffit pour démarrer ma propre solution.



1
votes

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 si vous le souhaitez, ou vous pouvez avoir une propriété sur l'interface révélant le type qu'elle gère et sélectionner dans une liste de gestionnaires (peut-être dépendants injectés) basés sur cette propriété.

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.)


0 commentaires

0
votes

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
    }
}


0 commentaires