2013-02-19 69 views
0

这篇文章基于我昨天的original post。但是我对我的需求不够精确,所以我会在这里再试一次。使用通用接口列表

请参阅我当前的代码:

public interface IPosterGenerator<T> 
{ 
    IQueryable<T> GetPosters(); 
} 

public class PetPosterGenerator : IPosterGenerator<PetPoster> 
{ 
    IQueryable<PetPoster> GetPosters() 
    { 
     return busLogic.GetPetPosters(); 
    } 
} 

public class FlowerPosterGenerator : IPosterGenerator<FlowerPoster> 
{ 
    IQueryable<FlowerPoster> GetPosters() 
    { 
     return busLogic.GetFlowerPosters(); 
    } 
} 

public class PinBoard 
{ 
    protected List<IPosterGenerator> PosterGenerators { get; set; } // 1. compiler error 

    public PinBoard(List<IPosterGenerator> generators) // 2. compiler error 
    { 
     this.PosterGenerators = generators; 
    } 

    public List<BasePoster> GetPosters() 
    { 
     var posters = new List<BasePoster>(); 

     foreach (var generator in PosterGenerators) 
     { 
      posters.Add(generator.GetPosters()); 
     } 

     return posters; 
    } 
} 

我的目标是创建一个“通知板”,它可以返回海报列表。每张海报可以是不同类型的(例如宠物海报,花海报等)。每张海报都有完全不同的外观,内容等等。但他们都继承了BasePoster类。

总而言之,我将有大约100种不同类型的海报。一个具体的PinBoard实例可以很容易地包含1000张海报和更多不同种类的海报(按照不同的顺序)。

为了填充某个PinBoard的海报,我需要给PinBoard提供一些海报生成器的列表(生成器的数量和类型将根据上下文而改变)。每个海报类型将会有一个海报生成器(例如,生成宠物海报的PetPosterGenerator)。

我认为这将是很好,如果我所有的海报生成器可以共享相同的(类型安全)接口。这就是我介绍IPosterGenerator接口的原因。

我的问题是代码不能编译。有两种编译器错误具有相同的错误消息:使用泛型类型“myApp.IPosterGenerator”需要1个类型参数

,因为我不定义任何类型的在这些位置,我没有错误消息感到惊讶。这将是巨大的,如果我能在第一个错误的线路做这样的事情:

protected List<IPosterGenerator<T>> PosterGenerators { get; set; } 

但是当我这样做,编译器无法找到类型或命名空间T.现在

我有点失落。毕竟,使用通用的IPosterGenerator接口可能不是一个好主意。但我确信,在我的应用程序中的某个时刻,我需要知道或访问某个IPosterGenerator所代表的具体海报类型。

你们会怎么做?非常感谢您提前给予您的支持。

+0

你得到错误的原因是很明显的。还有一种方法可以像其他人已经发布的那样来解决它,以创建一个通用接口来实现非通用接口。但是您应该考虑解决方案的整体设计!有什么不对吗.. – 2013-02-19 16:19:32

+0

@Miky:你可能是对的。除此之外,我不知道什么可能“不正确”;-) – Ingmar 2013-02-19 16:23:35

+0

问题是,您正在将一堆不同类型的'IPosterGenerator'对象混合到一个集合中。你可能不应该这样做,因为一旦你这样做了,你基本上“失去”了关于他们的一般论证的信息。你需要退后一步,思考你真正需要做的事情,而不是你需要做什么或者如何让代码编译,因为虽然这些问题是可以回答的,但它们的可能性很小真正帮助你。 – Servy 2013-02-19 16:25:12

回答

3

没有什么神奇的解决方案。如果你想使用泛型,你仍然需要使用它们。我的意思是你无法避免它们。

在另一方面,你可以为了充分利用协方差的让IPosterGenerator<T>T参数接受BasePoster

// Check the "out" keyword in the generic parameter! 
// "out" makes the T parameter covariant. 
public interface IPosterGenerator<out T> where T : BasePoster 
{ 
    IQueryable<T> GetPosters(); 
} 

现在你可以这样做:

public class PinBoard 
{ 
    protected List<IPosterGenerator<BasePoster>> PosterGenerators { get; set; } 

    public PinBoard(List<IPosterGenerator<BasePoster>> generators) 
    { 
     this.PosterGenerators = generators; 
    } 

    public List<BasePoster> GetPosters() 
    { 
     var posters = new List<BasePoster>(); 

     foreach (var generator in PosterGenerators) 
     { 
      posters.Add(generator.GetPosters()); 
     } 

     return posters; 
    } 
} 

那么容易! :)

+0

你的意思是你的界面定义有'where T:BasePoster'而不是':BasePoster'吗? – Servy 2013-02-19 16:27:01

+0

@Servy Ooops,是啊!固定。 – 2013-02-19 16:27:52

+0

哇。这看起来很不错。我可能不得不咀嚼一下。谢谢Matias! – Ingmar 2013-02-19 16:33:12

2

您通常会定义一个非泛型接口,然后让泛型接口继承它。像这样:

public interface IPosterGenerator 
{ 
    IQueryable GetPosters(); 
} 

public interface IPosterGenerator<T> : 
    IPosterGenerator 
{ 
    new IQueryable<T> GetPosters(); 
} 

要实现这个接口会你会做这样的事情

public class PetPosterGenerator : 
    IPosterGenerator<PetPoster> 
{ 
    IQueryable<PetPoster> GetPosters() 
    { 
     return busLogic.GetPetPosters(); 
    } 

    // Explicit interface implementation on non-generic method 
    IQueryable IPosterGenerator.GetPosters() 
    { 
     // Invokes generic version 
     return this.GetPosters(); 
    } 
} 
+0

所以我最终生成器类是这样的: 公共类PetPosterGenerator:IPosterGenerator { IQueryable的 IPosterGenerator .GetPosters(){ 扔 新NotImplementedException(); } IQueryable IPosterGenerator.GetPosters() throw new NotImplementedException(); } } – Ingmar 2013-02-19 16:20:44

+0

呃。格式不正确。对不起。 – Ingmar 2013-02-19 16:22:19

+0

@IngmarBode我添加了一个示例实现。 – 2013-02-19 16:25:52

1

有可能与仿制药:

public abstract class BasePoster { } 
public class PetPoster : BasePoster { } 
public class FlowerPoster : BasePoster { } 

// NOTE the out keyword here. 
public interface IPosterGenerator<out T> where T : BasePoster 
{ 
    IQueryable<T> GetPosters(); 
} 

public class PetPosterGenerator : IPosterGenerator<PetPoster> 
{ 
    public IQueryable<PetPoster> GetPosters() 
    { 
     return Enumerable.Range(0, 5).Select(i => 
     { 
      return new PetPoster(); 
     }).AsQueryable(); 
    } 
} 

public class FlowerPosterGenerator : IPosterGenerator<FlowerPoster> 
{ 
    public IQueryable<FlowerPoster> GetPosters() 
    { 
     return Enumerable.Range(0, 5).Select(i => 
     { 
      return new FlowerPoster(); 
     }).AsQueryable(); 
    } 
} 

public class PinBoard 
{ 
    protected List<IPosterGenerator<BasePoster>> PosterGenerators 
    { 
     get; 
     private set; // fixes compiler warning #1 
    } 

    public PinBoard(List<IPosterGenerator<BasePoster>> generators) // specify the generic type, fixes compiler warning #2 
    { 
     this.PosterGenerators = generators; 
    } 

    public List<BasePoster> GetPosters() 
    { 
     var posters = new List<BasePoster>(); 

     foreach (var generator in PosterGenerators) 
     { 
      posters.AddRange(generator.GetPosters()); // call AddRange not Add 
     } 

     return posters; 
    } 
} 

然后这个工程:

var generators = new List<IPosterGenerator<BasePoster>>(); 
generators.Add(new FlowerPosterGenerator()); 
generators.Add(new PetPosterGenerator()); 

var pinBoard = new PinBoard(generators); 
+0

非常感谢你的解决方案和你的努力。对此,我真的非常感激!不幸的是,马提亚斯快一点:-( – Ingmar 2013-02-19 16:34:49