2010-07-30 24 views
3

Vous rencontrez un problème avec le modèle de référentiel combiné à l'utilisation de classes abstraites.Problème avec le modèle de référentiel et les classes abstraites

J'ai un référentiel qui implémente une méthode unique renvoyant une ICollection d'un type abstrait.

Voici mon abstrait classe:

public abstract class Location 
{ 
    public abstract string Name { get; set; } 
    public abstract LocationType Type { get; } 
} 

Voici une concrète mise en œuvre de cette classe abstraite:

public class Country : Location 
{ 
    public override string Name { get; set; } 
    public override LocationType Type { get { return LocationType.Country; } } 
} 

Voici mon dépôt:

public class LocationsRepository : Locations.Repository.ILocationsRepository 
{ 
    public ICollection<Location> GetAllLocations() 
    { 
     Country america = new Country { Name = "United States" }; 
     Country australia = new Country { Name = "Australia" }; 
     State california = new State { Name = "California", Country = america }; 

     return new List<Location>() { america, australia, california }; 
    } 
} 

Tout va bien jusqu'ici.

Maintenant le service :

public class CountryService : ICountryService 
{ 
    private ILocationsRepository repository; 

    public CountryService() 
    { 
     // in reality this is done by DI, but made 'greedy' for simplicity. 
     this.repository = new LocationsRepository(); 
    } 

    public List<Country> GetAllCountries() 
    { 
     // errors thrown by compiler 
     return repository.GetAllLocations() 
         .Where(l => l.Type == LocationType.Country) 
         .ToList<Country>(); 
    } 
} 

Il y a le problème. J'essaie de renvoyer une liste de types concrets (Country) à partir d'un référentiel qui renvoie un ICollection<T> d'un type abstrait.

Obtenez 2 erreurs de compilation:

'System.Collections.Generic.IEnumerable' ne contient pas une définition pour 'ToList' et la meilleure méthode d'extension de surcharge « System.Linq. ParallelEnumerable.ToList (System.Linq.ParallelQuery) » a des arguments invalides

et

argument instance: ne peut pas convertir 'System.Collections.Generic.IEnumerable' à 'System.Linq.ParallelQuery'

Alors, comment puis-je mettre en œuvre ce modèle?

Je peux comprendre le problème (vous ne pouvez pas instancier un type abstrait), de même l'énumérateur (.ToList) tente-t-il d'instancier ce problème, d'où l'erreur?

Si vous ne comprenez pas ce que im essayant de faire:

  • Je veux que mon dépôt pour retourner un ICollection<T> d'un type abstrait
  • Je veux que mes services (je vais avoir un pour chaque béton type) pour renvoyer une liste de types concrets basée sur cette seule méthode de référentiel

Est-ce juste un cas de syntaxe LINQ? Ou mon modèle de conception est-il totalement faux?

Répondre

7
repository.GetAllLocations().OfType<Country>().ToList(); 

Et vous ne même pas besoin de la LocationType ENUM

+1

+1 C'est totalement la meilleure solution. –

+1

Génial, c'était donc un problème LINQ, pas un problème abstrait/référentiel. Merci!! – RPM1984

2

La solution à votre problème est assez facile, vous devez créer un nouveau pays dans l'expression LINQ:

return repository.GetAllLocations() 
    .Where(l => l.Type == LocationType.Country) 
    .Select(l => l as Country).ToList(); 

Je pense que vous confondez la méthode ToList<T> générique pour pouvoir créer une liste de nouveau type, où T est toujours déduit de la collection source. Généralement, chaque fois que vous voulez convertir une collection d'un type en une collection d'éléments d'un autre type, vous utilisez Select.

+0

Je crois Igor est correct - jeter un nouvel élément dans la clause select. Je fais cela tout le temps dans mes repos où je mappe des entités Linq à Sql à mes entités de domaine, et cette sélection en ligne() est précise. +1 J'utilise également des setters/gettings de propriétés internes, ce qui me permet de définir des internes à l'entité de domaine, qui utilise la logique pour rendre les membres supplémentaires accessibles publiquement. – eduncan911

+0

Cela fonctionne aussi - mais je penche pour @Necros réponse parce que, bien ... moins de code est meilleur (et il ne compte pas sur l'énumération) Quelqu'un peut-il envisager des différences entre cette réponse et @Necros réponse? – RPM1984