2017-08-04 11 views
0

J'ai trouvé cette question: Is it possible to specify a generic constraint for a type parameter to be convertible FROM another type? Je suis à la recherche d'un moyen plus intelligent.Déléguer le paramètre Method de IEnumerable <T> au type spécifique

Class A { 
    public A(string){} 
} 

Class foo 
{ 
    private List<A> content = new List<A>(); 

    public void Add(A a){ 
     content.Add(a); 
    } 
    public void Add(string str){ 
     content.Add(new A(str)); 
    } 
    public void AddRange<T>(IEnumerable<T> iterable) // where T : ??? 
    { 
     foreach(T t in iterable) 
      content.Add((A)t); //Error 
    } 
} 

L'erreur est:

Cannot convert type 'T' to 'A'

Question: une expression where T : ? Exists comme "convertable"?

Mise à jour: J'ai deux méthodes: Add(A) surcharges et Add(string) i essayer actuellement de convertir T à A. Mais mon principal problème est que je veux utiliser différentes méthodes Add relatives à T. Ce que je besoin est quelque chose comme:

public void AddRange<T>(IEnumerable<T> iterable) where T : Add(T) 
{ 
    foreach (T t in iterable) 
     this.Add(t); 
} 
+7

Ce que vous essayez d'obtenir n'est pas clair. Ne veux-tu pas juste "où T: A'? –

+0

Que signifie "convertable"? –

+0

Je veux appeler Ajouter avec deux différents types énumérables: Liste et Liste . – Syrlia

Répondre

3

Je pense que ce que vous cherchez contrainte de saisir qui doit avoir explicitement opérateur T, mais étant donné que la spécification dit:

conversion-operator-declarator: 
    implicit operator type ( type identifier ) 
    explicit operator type ( type identifier )

WHI ch signifie généralement que vous ne pouvez pas avoir un opérateur explicite et implicite générique, je ne pense pas que ce soit possible.

Vous pouvez faire votre cas possible si vous avez des types concrets mais comme ceci:

public class A 
{ 
    public static explicit operator B(A a) 
    { 
     return new B(); 
    } 
} 

public class B { } 

public class Convert 
{ 
    public static T To<T>(dynamic obj) 
    { 
     return (T) obj; 
    } 
} 

class Foo 
{ 
    private List<A> content = new List<A>(); 
    public void AddRange<T>(IEnumerable<T> iterable) where T : B 
    { 
     foreach (T t in iterable) 
      content.Add(Convert.To<A>(t)); // This will invoke the implicit operator defined in A 
    } 
} 

Peut-être que vous pouvez abstraites vos T génériques types être de type de type B et limiter comme ça, ou peut-être vous définissez tous les opérateurs implicites des types qui veulent que vous convertissiez en A dans le type T.

1

Si vous voulez T être le type A ou toute utilisation de type dérivé where T : A.

EDIT (après votre commentaire):

Si vous voulez T être A ou String vous ne pouvez pas faire quelque chose comme ceci: where T : A, String. Vous pouvez limiter la classe, l'interface, le type, mais il n'est pas possible d'effectuer l'opération OR. Donc, dans votre cas si vous voulez seulement String ou A alors vous devriez utiliser différentes implémentations. Si vous voulez une classe - where T : class

+0

J'ai eu cette erreur: 'chaîne' n'est pas une contrainte valide. Un type utilisé comme contrainte doit être une interface, une classe non scellée ou un paramètre de type. – Syrlia

+0

@Syrlia, quand obtenez-vous cette erreur? Si vous essayez de contraindre uniquement 'String', vous échouerez car' String' est 'sealed' et les contraintes sur les classes' sealed' ne sont pas autorisées (pas de raison). Dire différentes implémentations, je veux dire deux surcharges - si vous voulez seulement deux types, vous devriez avoir deux surcharges - il n'y a pas besoin de génériques dans ce cas. –

+0

Deux autres implémentations ne posent aucun problème, mais je veux l'apprendre pour les gros cas. Ceci est seulement un exemple. ;-) J'ai eu l'erreur en la changeant en: 'AddRange (IEnumerable iterable) où T: A, string' – Syrlia

0

Vous pouvez utiliser A au lieu de T:

public void Add(IEnumerable<A> iterable) 
{ 
    foreach(A t in iterable) 
     content.Add(t); 
} 

et:

public void Add(IEnumerable<string> iterable) 
{ 
    foreach(string t in iterable) 
     content.Add(t); 
} 
+0

Si je fais et essaie d'appeler 'AddRange (nouvelle liste ()': "Argument 1: impossible de convertir de 'System.Collections.Generic.List ' en System.Collections.Generic.IEnumerable '" – Syrlia

+0

Vous devez ajouter deux méthodes, car 'chaîne' n'est pas une contrainte valide (pour la clause where) car il s'agit d'une classe scellée. –