2009-02-03 5 views
1

J'ai un ensemble de classes qui sont toutes capables d'être construites avec un argument étant une instance d'une interface particulière. Puisqu'ils peuvent tous être construits par ce même objet (et le processus au cours duquel cette construction se produit est en grande partie le même dans tous les cas), j'ai pensé que peut-être que le modèle fonctionnerait. Au fond, je veux faire quelque chose comme ceci:Modèles C# et constructeurs spéciaux

public static void dostuff<T, U> (List<T> items) 
{ 
    foreach (T item in items) 
    { 
     func(new U(item).SpecialMember); 
    } 
} 

Bien sûr, cela ne compilera pas depuis U est basé sur un modèle et ne dispose pas ainsi SpecialMember ainsi que le constructeur T. Fondamentalement, toute implémentation donnée de l'inteface T a certaines caractéristiques. U est une implémentation de T which has an additional feature that is needed *and* which can be constructed from an any instance of U`.

Conseil?

Répondre

4

Malheureusement, alors que les contraintes vous obtiendrez une du chemin, il n'y a aucun moyen de spécifiez qu'un type a un constructeur qui prend certains arguments: le seul constructeur dont vous pouvez avoir besoin est un constructeur sans paramètre.

Personnellement, je voudrais voir que le changement en utilisant une idée de "static interfaces" (utilisable uniquement pour des contraintes de type), mais pour le moment le meilleur que vous obtiendrez est une usine de type ou de réflexion - ou peut-être un constructeur parameterless et une méthode "Init" dans l'interface. Aucun d'entre eux sont de bonnes options, franchement.

0

Vous souhaitez un modèle Factory. Ajoutez une méthode usine à votre interface T qui renvoie les types U.

2

Vous pouvez ajouter constraints aux paramètres génériques qui vous permettront d'accéder à SpecialMember par exemple:

public class SpecialObjFactory<T,U> where T : ISpecialMethod 
where u : new() 
{ 
} 
0

Vous ne pouvez pas utiliser les médicaments génériques pour créer un objet comme celui-ci. Vous pouvez contraindre les types génériques comme ceci:

public static void dostuff<T, U> (List<T> items) where T : SomeClass where U : SomethingElse 
{ 
} 

Mais cela ne vous permettra d'accéder à des membres de ces classes/interfaces, pas de constructeurs.

Pour développer la réponse de Joel, vous devez ajouter une méthode à l'interface T (dans mon exemple, SomeClass) qui prend un objet T et retourne un nouvel objet U. Quelque chose comme ce qui suit:

public class SomeClass  
{ 
    CreateInstanceOfSomethingElse() { return new SomethingElse(this); } 
} 

public static void dostuff<T, U> (List<T> items) where T : SomeClass, U : SomethingElse 
{ 
    foreach (T item in items) 
    { 
     func(item.CreateInstanceOfSomethingElse().SpecialMember); 
    } 

} 

Comme une autre approche complètement différente, vous pouvez spécifier que la méthode doStuff prend un Func<T, U> aussi bien, qui est censé créer un U à partir d'un objet T.

public static void dostuff<T, U> (List<T> items, Func<T, U> createU) 
{ 
    foreach (T item in items) 
    { 
     func(createU(item).SpecialMember); 
    } 

} 

Cela devient malpropre si votre création d'objets est quelque chose de plus complexe qu'un simple lamba comme

t => new U(t)

0
public static void dostuff<T, U> (List<T> items) 
{ 
    foreach (T item in items) 
    { 
     U obj = (U)System.Activator.CreateInstance(typeof(U), item); 
     func(obj.SpecialMember); 
    } 
} 
Questions connexes