0

この投稿は、昨日の私の元の投稿に基づいています。しかし、私は自分のニーズについて十分に正確ではなかったので、ここでもう一度やり直します.

私の現在のコードを見てください:

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 に特定のポスター ジェネレーターのリストを入力する必要があります (ジェネレーターの量と種類はコンテキストに応じて変わります)。ポスター タイプごとに 1 つのポスター ジェネレーターがあります (たとえば、ペット ポスターのコレクションを生成する PetPosterGenerator)。

すべてのポスター ジェネレーターが同じ (タイプ セーフな) インターフェイスを共有できればいいと思いました。そのため、IPosterGenerator インターフェイスを導入しました。

私の問題は、コードがコンパイルされないことです。同じエラー メッセージを伴う 2 つのコンパイラ エラーがあります: Using the generic type 'myApp.IPosterGenerator' requires 1 type arguments

これらの場所でタイプを定義していないため、エラー メッセージに驚くことはありません。最初のエラーの行で次のようなことができれば素晴らしいでしょう:

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

しかし、これを行うと、コンパイラは型または名前空間 T を見つけることができません。

今、私はちょっと迷っています。結局、一般的な IPosterGenerator インターフェースを使用することはあまり良い考えではないかもしれません。しかし、アプリケーションのある時点で、特定の IPosterGenerator が表す具体的なポスターの種類を知るかアクセスする必要があると確信しています。

皆さんはこれにどのようにアプローチしますか?よろしくお願いいたします。

4

3 に答える 3

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();
    }
}
于 2013-02-19T16:16:20.277 に答える
2

魔法の解決策はありません。ジェネリックを使用する場合でも、それらを使用する必要があります。つまり、それらを避けることはできません。

一方、共分散を利用して、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;
    }
}

とても簡単!:)

于 2013-02-19T16:25:28.310 に答える
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);
于 2013-02-19T16:28:25.247 に答える