2009-06-01 7 views
4

J'essaie d'ajouter une autre restriction à une méthode dans une classe générique. Est-ce possible?C#: Ajouter une méthode générique conditionnelle (restriction générique différente) dans la classe générique

pseudocode:

public class MyBaseClass<T> where T: class 
{ 
    public IQueryable<T> ShowThisMethod where T: class, IMyInterface 
    { 
     // stuff. 
    } 
} 

ShowThisMethod ne devrait être disponible que lorsque T est IMyInterface. IMyInterface devrait aussi redonner des informations (à propos de T) afin que je puisse accéder aux propriétés définies dans IMyInterface à l'intérieur de la méthode.

Aide :)

Par ailleurs, cette compile (et semble "presque droite"):

public class MyBaseClass<T> where T: class 
{ 
    public IQueryable<T> ShowThisMethod<T>() where T: class, IMyInterface 
    { 
     String X = T.MyInterfaceStringProperty; 
    } 
} 

Plus d'informations au sujet de mon objectif:

I utilise une classe de base générique pour accéder à une propriété commune (propriété DateTime "Time" sur l'objet LINQ Dinner qui est également sur Déjeuner).

Les deux objets implémentent ITimeable qui expose la propriété DateTime.

Dans ma classe de base, je voudrais avoir une méthode Select() qui fonctionne sur IQueryable & ltT> et peut filtrer automatiquement en fonction de la propriété Time. Parce que je travaille hors du générique T, la propriété time n'est pas visible à la classe de base, sauf si je lui dis que T est en train d'implémenter ITimeable. Je souhaite que la même classe de base fonctionne pour d'autres objets non-ITimeable, c'est pourquoi j'ai besoin de la restriction d'interface sur la méthode Select, et j'en ai besoin pour accéder à la propriété Time en utilisant des génériques.

espoir qui efface le but :)

post-scriptum Ma principale préoccupation n'est pas la visibilité de la méthode dans IntelliSense, etc.. Je voudrais simplement que ma classe de base fonctionne, tout en étant capable d'accéder à une propriété spécifiée par l'interface via des génériques.

+0

Ce second code ne compile pas pour moi, je reçois un message d'erreur indiquant que le paramètre de type « T » a le même nom que le paramètre type du type externe '... MyBaseClass '. –

+0

Je reçois cela comme un avertissement aussi, oui, mais compile pour moi. – Alex

+0

Ce n'est pas la même chose que de redéfinir les contraintes. Fondamentalement, vous pouvez avoir quelque chose comme MyBaseClass .ShowThisMethod (), par exemple. Je doute que ce soit ce que tu veux. –

Répondre

3

Cela dépend de ce que vous voulez. Puisque la classe est compilée une fois, et que la magie avec les génériques repose aussi sur l'exécution, il est impossible de créer une classe qui a des méthodes dans certains cas, et d'autres méthodes dans d'autres cas. Soit les méthodes sont là, soit elles ne le sont pas.

Donc, fondamentalement, il n'y a aucun moyen de déclarer MyBaseClass de telle sorte que les éléments suivants se produit:

MyBaseClass<Int32> bc; 
bc. <-- intellisense does not show ShowThisMethod here 

MyBaseClass<SomeTypeImplementingIMyInterface> bc2; 
bc2. <-- intellisense DOES show ShowThisMethod here 

... qui est ... par lui-même.

Vous pouvez "tromper" le compilateur et intellisense en vous donnant ce que vous demandez, mais sachez que cela vous donne d'autres limitations et défis qui pourraient avoir besoin d'être résolus. Fondamentalement, en ajoutant une méthode d'extension à une classe statique déclarée à côté de MyBaseClass, vous pouvez faire en sorte que intellisense, et le compilateur, se comportent comme si la méthode n'était présente que pour MyBaseClass quand T a des règles spécifiques, comme vous le demandez pour. Cependant, comme la méthode en question sera une méthode statique, définie en dehors de MyBaseClass, il y a des limites à la quantité d'internes de MyBaseClass auxquelles vous pouvez accéder, et vous ne pouvez pas accéder à la méthode dans MyBaseClass, donc cela dépend sur ce que vous voulez accomplir et si vous pouvez vivre avec les limitations ou non.

Quoi qu'il en soit, voici la méthode d'extension. Notez que vous le supprimez complètement de MyBaseClass en même temps:

public static class MyBaseClassExtensions 
{ 
    public static IQueryable<T> ShowThisMethod<T>(this MyBaseClass<T> mbc) 
     where T: class, IMyInterface 
    { 
     ... 
    } 
} 
+0

Ajoutez plus d'informations sur mon objectif. – Alex

+0

Vous êtes une rock star !! – Alex

+0

Je vous remercie de le dire, mais gardez l'éloge pour quand vous avez joué un peu avec la méthode d'extension. Je suis assez sûr qu'il y a des pièges là-bas que vous ne voyez pas, au moins j'ai ce sentiment lancinant ... :) –

1

Non, ce n'est pas possible. Les contraintes sont définies lorsqu'elles sont déclarées. Dans ce cas, la méthode n'est pas générique, la classe est (c'est une méthode non générique d'une classe générique). Ainsi, les contraintes ne peuvent être déclarées que sur la classe elle-même.

1

Cela fera-t-il ce que vous voulez? La méthode sera visible à tout le monde, mais pas nécessairement utilisable ...

public class MyBaseClass<T> where T: class 
{ 
    public IQueryable<R> ShowThisMethod() where R: T, IMyInterface 
    { 
     Debug.Assert(typeof(R) == typeof(T)); 
     // stuff. 
    } 
} 
+0

Cela ne fonctionne pas ... – Alex

2

Notez également que ShowThisMethod est redéfinition T dans le contexte de ShowThisMethod. Ce n'est pas le même que celui défini par la classe.

Spécifier un paramètre Type différent où le nouveau hérite de celui défini par la classe serait la meilleure approche, bien que cela finisse par requérir que l'appelant spécifie deux fois le Type générique.

1

Vous pouvez définir une autre classe qui hérite MyBaseClass et de redéfinir la contrainte:

public MyOtherClass<T> : MyBaseClass<T> where T : class, IMyInterface 
{ 
    public IQueryable<T> ShowThisMethod() 
    { 
     // stuff. 
    } 
} 
Questions connexes