6Fermer8
GoldenCrystalLe 28/07/2009 à 17:43
Ce genre de problèmes est assez ennuyeux oué (ne pas pouvoir spécialiser soi même un type générique) mais tu peux souvent t'en sortir de diverses façons.
Ton problème vient du fait que tu n'imposes pas de contrainte sur ton T. Dès lors, T peut être n'importe quoi, donc tu n'as aucune garantie que ce type implémente une méthode particulière.
Après il faut savoir (les raisons derrière tout ça, etc...), pas spécialement pour répondre à Zephyr, mais c'est toujours utile à savoir, que les tous les contrats en C# sont des contrats forts (les interfaces, qu'il faut explicitement implémenter... Il y aura le type dynamic pour remédier à ça en C# 4.0 mais ça ne s'appliquera pas vraiment de manière intéressante au cas présent je pense), et que les contraintes de types génériques sont quasi uniquement basées sur des contrats forts (il y a l'exception du new() et du class/struct, mais je crois que c'est tout).
Ce qui simplifierait tout serait la possibilité de spécialiser les interfaces soit même, ce qui revient en quelque sorte à la méthode de ./1, mais en mieux quand même, puisque la spécialisation serait transparente à l'utilisateur. (Pour ce qui est de la faisabilité au niveau du CLR j'en sais fichtrement rien après sad)

Pour ce qui est des solutions concrètes au problème, j'en vois basiquement deux.
1. La méthode que tu as choisie en ./1 ... A l'exception faite que si ton problème se situe au niveau de la méthode Machin.Methodeode (value)); } protected abstract Int32 Methode(T value); }
, c'est cette méthode (seule) que tu dois surcharger dans ta classe: abstract class MaClasse<T> 
{ 
    public void Test (T value) 
    { 
        Console.WriteLine (Meth

2. Utiliser une interface générique implémentant la méthode de tes désirs, ce qui est utilisé par exemple par le Dictionary<TKey,TValue> de la BCL actuelle.
interface IHasMethod<T>
{
    int Methode(T value);
}
Il te suffit ensuite de demander qu'on te fournisse cette interface quelque part dans ton constructeur, et d'accepter ou refuser, de gérer un comportement par défaut (par exemple, réflexion, ou accepter que le type "T" définisse lui même l'interface, etc ^^) dans ta classe.
Ce qui se simplifie évidemment grandement si (et seulement si) tu as le contrôle de ta classe Machin }
: public static class Machin : IHasMethod<A>, IHasMethod<B>, IHasMethod<C>
{ 
    Int32 Methode (A value) { ... } 
    Int32 Methode (B value) { ... } 
    Int32 Methode (C value) { ... } 


Après, les deux méthodes sont relativement équivalentes, mais je pense que l'une est préférable à l'autre selon les cas.
Typiquement, la première méthode s'appliquerait mieux dans le cas où tu veux améliorer le fonctionnement de la classe pour un ou deux types spécifiques, mais où elle fonctionne déjà pour pratiquement tout de base, tandis que la seconde méthode évite de devoir bidouiller la "machinerie interne" de ta classe (à priori j'aura tendance à dire que c'est ton cas en ./1 mais j'en sais peut-être pas assez), et ou tu peux ainsi limite la sceller (sealed c le bien... même si pour l'instant le JIT n'en tire aucune optimisation sad).

Tu peux après pousser un peu le vice pour la méthode 2:
>(); else if (StandardMethods.Default is IHasMethod<T>) methodOwner = StandardMethods.Default as IHasMethod<T>; else throw new InvalidOperationException(); } public void Test(T value) { Console.WriteLine(methodOwner.Method(value)); } }
1. Prévoir une implémentation par défaut pour tous les types que tu connais, autoriser le type à définir lui même la méthode, accepter une méthode spéciale via un paramètre  spécifique (éventuellement même avec un délégate...), et, pourquoi pas, offrir une alternative standard via la réflexion ou autre:sealed class StandardMethods : IHasMethod<A>, ...
{
    public static readonly StandardMethods Default = new StandardMethods();
    public int Method(A value) { ... }
}
class MyClass<T> 
{
    sealed class TypeHasMethod<T> : IHasMethod<T>
        where T : IHasMethod<T>
    {
        int Method(T value) { value.Method(value); }; // Ouais c'est complètement con comme implémentation mais ça fonctionne #trioui#
    }
    IHasMethod<T> methodOwner;

    public MyClass() : this(null) { }

    public MyClass(IHasMethod<T> methodOwner)
    {
        if (methodOwner != null)
            this.methodOwner = methodOwner;
        else if (typeof(IHasMethod<T>).IsAssignableFrom(typeof(T)))
            methodOwner = new TypeHasMethod<T
(J'avoue j'ai pas testé le code mais c'est l'idée générale quoi)