2010-03-02 2 views
1

On suppose certains objets de domaine et afficher (qui ont pas de classe de base commune)Comment puis-je créer une méthode générique pour convertir des listes d'objets lorsque des méthodes de conversion pour des objets uniques existent?

public class DomainA 
{ 
    public int MyProperty { get; set; } 
} 

public class ViewA 
{ 
    public int MyProperty { get; set; } 
} 

public class DomainB 
{ 
    public string MyProperty { get; set; } 
} 

public class ViewB 
{ 
    public string MyProperty { get; set; } 
} 

et une classe qui peut convertir domaine à la vue correspondante

public class ViewFactory 
{ 
    public static ViewA Create(DomainA value) 
    { 
     return new ViewA() { MyProperty = value.MyProperty }; 
    } 

    public static ViewB Create(DomainB value) 
    { 
     return new ViewB() { MyProperty = value.MyProperty }; 
    } 
} 

Est-il possible d'écrire une méthode le long de la lignes de

public static List<T> Create<T, U>(IEnumerable<U> values) 
{ 
    return new List<T>(from v in values where v != null select Create((U)v)); 
} 

qui peut convertir les listes des objets « domaine » aux listes des objets « vue » étant donné qu'il existe déjà meth ods pour convertir un seul objet?

Je me sens comme si je manque quelque chose de vraiment stupide et de base sur les médicaments génériques demandant ce question..better d'apprendre la réponse que de rester désemparés si :)

Répondre

2

Oui si vous modifiez votre fonction Créer de prendre une correspondance entre le domaine et offre une vue:

public static List<T> Create<T, U>(IEnumerable<U> values, Func<U, T> mapFunc) 
{ 
    return values.Select(v => mapFunc(v)).ToList(); 
} 

Vous pouvez ensuite faire la mise en correspondance utilisant vos méthodes ViewFactory:

IEnumerable<DomainA> domAs = //whatever 
var aViews = Create(domAs, a => ViewFactory.Create(a)); 
+0

Merci cela devrait être exactement ce dont j'ai besoin. – Jedidja

+0

En fait, pourrais-je faire le Func implicite? Étant donné qu'il est toujours appelé Créer? Je préférerais ne pas avoir à le transmettre à chaque fois. – Jedidja

2

vous devriez être en mesure d'utiliser le ConvertAll et ToList Fonctions

ConvertAll vous permet de projeter vos modifications qui rentreraient un IEnumerable de T dans votre cas, puis un ToList convertirait du IEnumerable à la liste

donc volé de l'article MSDN

 List<PointF> lpf = new List<PointF>(); 

    lpf.Add(new PointF(27.8F, 32.62F)); 
    lpf.Add(new PointF(99.3F, 147.273F)); 
    lpf.Add(new PointF(7.5F, 1412.2F)); 

    Console.WriteLine(); 
    foreach(PointF p in lpf) 
    { 
     Console.WriteLine(p); 
    } 

    List<Point> lp = lpf.ConvertAll( 
     new Converter<PointF, Point>(PointFToPoint)); 

    Console.WriteLine(); 
    foreach(Point p in lp) 
    { 
     Console.WriteLine(p); 
    } 

vous devriez être en mesure d'aller de U à T comme ils sont passés de PointF au point

vous ne pouvez pas besoin même le ToList

2

Vous ne devriez pas avoir besoin d'une méthode personnalisée pour créer les listes. Vous pouvez simplement effectuer les opérations suivantes:

List<DomainA> domains = GetDomainList(); 
List<ViewA> views = domains.ConvertAll<ViewA>(x => ViewFactory.Create(x)); 
1

Hmm, il me semble que vous avez besoin d'un modèle plus orienté objet plutôt que les médicaments génériques:

public abstract class Domain 
{ 
    public abstract View CreateView(); 
} 

public abstract class View 
{ 
} 

public class DomainA : Domain 
{ 
    public int MyProperty { get; set; } 

    public override View CreateView() 
    { 
     return new ViewA() { MyProperty = value.MyProperty }; 
    } 
} 

public class ViewA : View 
{ 
    public int MyProperty { get; set; } 
} 

public class DomainB : Domain 
{ 
    public string MyProperty { get; set; } 

    public override View CreateView() 
    { 
     return new ViewB() { MyProperty = value.MyProperty }; 
    } 
} 

public class ViewB : View 
{ 
    public string MyProperty { get; set; } 
} 
+0

Je préfère ne pas jouer avec le modèle de la classe. – Jedidja

+0

Vous avez cependant quelques avantages, au cas où ils auraient une fonctionnalité plus "personnalisée". Ou si vous voulez créer une liste de vues, par exemple. –

+0

@Jedidja On dirait que vous essayez d'utiliser un marteau de programmation générique où un rochet de programmation orienté objet conviendrait mieux. Vous avez lié conceptuellement aux articles; les deux classes Domain implémentent l'interface IViewable {T CreateView(); } et avance. –

1

Vous ne pouvez pas créer une méthode générique comme vous essayons de faire. Dans votre exemple, il n'y a que quelques façons de définir T et U qui fonctionneraient (par exemple Create<ViewA,DomainA>(domains) serait significatif, mais Create<string,int>(ints) ne serait pas). L'appelant d'une méthode générique décide à quels types l'appeler, de sorte que les méthodes génériques doivent fonctionner pour tous les paramètres de type, ce qui n'est pas le cas de votre méthode.

D'autres ont donné plusieurs bonnes suggestions pour atteindre le résultat souhaité.

0

Finalement, il semble que vous voulez est une petite chose appelée multiple dispatch. Ce qui, malheureusement, pour nous tous n'est pas implémenté dans C# 3. Si vous voulez que votre programme détermine automagiquement la méthode à appeler, vous devrez soit utiliser la réflexion ou une fonction virtuelle en utilisant une seule répartition.

interface IViewFactory<TView, TDomain> 
{ 
    TView Create(TDomain domain); 
} 

class ViewFactoryA : IViewFactory<ViewA, DomainA> 
{ 
    ... 
} 
class ViewFactoryB : IViewFactory<ViewB, DomainB> 
{ 
    ... 
} 

maintenant votre code d'initialisation a juste besoin de créer l'objet usine correct.

Questions connexes