2010-08-24 4 views
2

Je travaille sur une fonction déléguée générique et déclare un type de liste de types de retour.C# Instanciation d'objet générique avec type générique

public static List<T> PerformOperationOnGenericArray<T>(IList<T> myList, 
    FunctionForGenericArray<T> operation) 

Suis-je capable d'utiliser un type générique de retour au lieu de la liste qui indique également un type générique, à savoir S

public static S<T> PerformOperationOnGenericArray<T, S>(IList<T> myList, 
    FunctionForGenericArray<T> operation) 

Je suppose que cela est impossible, mais je ne vois pas la raison pourquoi pas. Le compilateur sait sûrement le type quand je précise:

PerformOperationOnGenericArray<int, List<string>>(myInts, i => i.Equals(12)); 

Est-ce peut-être une situation dans laquelle je dois regarder en utilisant des types dynamiques?

Répondre

3

Vous ne pouvez pas utiliser un type générique ouvert comme un paramètre de type générique, cependant, vous pouvez utiliser un type spécifique S<T> comme paramètre:

public static R PerformOperationOnGenericArray<T,R> 
      (IList<T> myList, FunctionForGenericArray<T> operation) 
    where R : S<T> 

Dans votre cas, si le type S est entièrement défini (type fermé) au moment de la compilation, vous n'avez même pas besoin de faire cela:

public static S<T> PerformOperationOnGenericArray<T> 
      (IList<T> myList, FunctionForGenericArray<T> operation) 

devrait suffire.

Vous devez uniquement utiliser le premier formulaire si S lui-même varie. Alors qu'est-ce que je veux dire par là. Regardons un exemple. Si vous avez:

class Foo<T> { } 

vous pouvez écrire:

public static Foo<T> PerformOperationOnGenericArray<T> 
      (IList<T> myList, FunctionForGenericArray<T> operation) 

Mais, si vous avez un groupe de types génériques connexes:

class Foo<T> { } 
class Bar<T> : Foo<T> { } 
class Baz<T> : Foo<T> { } 

et que vous voulez permettre à l'appelant de spécifier celui à utiliser, alors vous devez faire le type de retour partie de la signature générique de la méthode:

public static R PerformOperationOnGenericArray<T,R> 
      (IList<T> myList, FunctionForGenericArray<T> operation) 
    where R : Foo<T> 

où les appelants devront maintenant préciser le type de R explicitement:

PerformOperationOnGenericArray<T,Bar<T>>(...) 

Si vous souhaitez autoriser tout type générique qui accepte un seul paramètre autorisé, vous êtes là hors de la chance. Le système de type ne fournit pas un moyen d'exprimer la restriction:

allow any generic type that allows a single parameter, and enforce that parameter to be a T

Le mieux que vous pouvez faire est de définir une interface bien connu que tous les types connus sont conformes à (comme IEnumerable<T>, ou celui que vous vous cRAFT), et utiliser que dans le cadre de la contrainte générique:

public static R PerformOperationOnGenericArray<T,R> 
      (IList<T> myList, FunctionForGenericArray<T> operation) 
    where R : IEnumerable<T> 

Cependant, dans ce cas, les types fournis doivent tous mettre en œuvre cette interface. Si vous cherchez le premier (où vous pouvez spécifier n'importe quel type qui doit correspondre au nombre de paramètres de type), vous recherchez duck typing(1) générique - ce que C# ne supporte pas.

Une note intéressante à ce sujet. Créer une méthode générique dont les types ne peuvent pas être déduits par le compilateur uniquement à partir des paramètres formels de la méthode est quelque chose à essayer d'éviter. Lorsque les paramètres ne peuvent pas être déduits, l'appelant est obligé de spécifier tous les paramètres de type - ce qui conduit à un code confus et bavard. Bien que ces situations surviennent parfois, il est préférable d'essayer de les éviter, dans la mesure du possible.

(1)- C# prend en charge la saisie de canard dans les types anonymes dans un seul ensemble si les types correspondent dans l'ordre, les types et les noms de leurs membres - sur lesquels le compilateur suppose qu'ils sont le même type.

+0

Merci pour la réponse. Malheureusement, j'ai essayé votre deuxième suggestion et le compilateur n'aime pas S. Je reçois "Unknown Entity 'S" " –

+0

@Ryan - la deuxième forme exige que" S "soit un type réel. Ce n'est pas destiné à être un paramètre de type. Si 'S' est lui-même un paramètre de type, alors vous devez ** utiliser ** le premier formulaire. Je mettrai à jour ma réponse pour le rendre plus clair. – LBushkin

+0

Ah ... désolé j'ai mal lu ce que vous disiez. Cela a du sens maintenant merci pour la clarification. Ce n'est pas quelque chose qui va en production. Il suffit de regarder les limites du typage générique sur les fonctions de délégué. –

Questions connexes