2012-04-18 14 views
-1

私は既にthis question with a bad sampleを投稿しました。C#で一般的な多型を実装する方法 - 第2部

このコードはよりよいはずです。私はライン12

Main()でInvalidCastExceptionが取得するコードをデバッグするとき

using System.Collections.Generic; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main() 
     { 
      IManager<ISpecificEntity> specificManager = new SpecificEntityManager(); 
      IManager<IAntoherSpecificEntity> anotherSpecificManager = new AnotherSpecificEntityManager(); 
      Dictionary<string, IManager<IIdentifier>> managers = new Dictionary<string, IManager<IIdentifier>>(); 
      managers.Add("SpecificManager", (IManager<IIdentifier>)specificManager); 
      managers.Add("AnotherSpecificManager", (IManager<IIdentifier>)anotherSpecificManager); 

      foreach (var manager in managers.Values) 
      { 
       IIdentifier entity = manager.Container.GetEntity(); 
      } 
     } 
    } 

    internal interface IIdentifier 
    { 
     int Id { get; set; } 
    } 

    internal interface ISpecificEntity : IIdentifier 
    { 
     string SpecificValue { get; set; } 
    } 

    internal class SpecificEntity : ISpecificEntity 
    { 
     public int Id { get; set; } 
     public string SpecificValue { get; set; } 
    } 


    internal interface IAntoherSpecificEntity : IIdentifier 
    { 
     string AnotherSpecificValue { get; set; } 
    } 

    internal class AntoherSpecificEntity : IAntoherSpecificEntity 
    { 
     public int Id { get; set; } 
     public string AnotherSpecificValue { get; set; } 
    } 

    internal interface IContainer<out TIdentifier> where TIdentifier : IIdentifier 
    { 
     TIdentifier GetEntity(); 
    } 

    internal interface ISpecificContainer : IContainer<ISpecificEntity> 
    { 
    } 

    internal class SpecificContainer : ISpecificContainer 
    { 
     public ISpecificEntity GetEntity() 
     { 
      return new SpecificEntity { SpecificValue = "SpecificValue" }; 
     } 
    } 

    internal interface IAnotherSpecificContainer : IContainer<IAntoherSpecificEntity> 
    { 
    } 

    internal class AnotherSpecificContainer : IAnotherSpecificContainer 
    { 
     public IAntoherSpecificEntity GetEntity() 
     { 
      return new AntoherSpecificEntity { AnotherSpecificValue = "AnotherSpecificValue" }; 
     } 
    } 

    internal interface IManager<TIdentifier> where TIdentifier : IIdentifier 
    { 
     IContainer<TIdentifier> Container { get; set; } 
    } 

    internal class SpecificEntityManager : IManager<ISpecificEntity> 
    { 
     public IContainer<ISpecificEntity> Container { get; set; } 
    } 

    internal class AnotherSpecificEntityManager : IManager<IAntoherSpecificEntity> 
    { 
     public IContainer<IAntoherSpecificEntity> Container { get; set; } 
    } 
} 

私はISpecificEntityIIdentifierを実装していることを知っている:混乱を避けるために

は、私はいくつかのコードをまとめました。 しかし、明らかにIManager<ISpecificEntity>からIManager<IIdentifier>への直接キャストは機能しません。

私は共分散を使って作業することはできますが、IManager<in TIdentifier>またはIManager<out TIdentifier>IManager<TIdentifier>を変更することはできません。

したがって、specificManagerIManager<IIdentifier>にキャストする方法はありますか?

ありがとうございました。

+1

それが問題であるメインのライン()あなたを教えてください。それを教えてください。 –

+0

[C#で一般的な多態性を実装する方法]の複製が可能です(http://stackoverflow.com/questions/10211072/how-to-implement-generic-polymorphism-in-c) –

+0

再ポスト、編集、改善しないでくださいあなたの質問。 –

答えて

1

まず第一に、ジェネリックスが間違っているという考えがあります。

あなたがFooを見ているのは、ジェネリック型です。 FooとFooは新しい型であり、Listから派生したものではなく、型は継承によってconnetされません。 ジェネリックを使用すると新しい型が作成されますが、その型は派生しません!

しかし、あなたが探しているのはCovariance and Contravarianceです。これにより、一種の「汎用多型」を作成することができますが、そのために汎用の定義に指定する必要があります。したがって、それは非常に少数のフレームワークジェネリックのためだけに機能します。ここで

class Program 
{ 
    static void Main(string[] args) 
    { 
     IManager<IIdentifier> f1 = new C1(); 
     IManager<IIdentifier> f2 = new SpecificEntityManager(); //IManager<ISpecificEntity> 
    } 
} 

interface IIdentifier { } 
interface ISpecificEntity : IIdentifier { } 
interface IManager<out T> { } 

class C1 : IManager<IIdentifier> { } 
class SpecificEntityManager : IManager<ISpecificEntity> { } 

は、変更しなければならないものである:

internal interface IContainer<out TIdentifier> where TIdentifier : IIdentifier 
{ 
    TIdentifier GetEntity(); 
} 
internal interface IManager<out TIdentifier> where TIdentifier : IIdentifier 
{ 
    IContainer<IIdentifier> Container { get; } 
} 
internal class SpecificEntityManager : IManager<ISpecificEntity> 
{ 
    public IContainer<IIdentifier> Container { get; set; } 
} 
internal class AnotherSpecificEntityManager : IManager<IAntoherSpecificEntity> 
{ 
    public IContainer<IIdentifier> Container { get; set; } 
} 
+0

あなたは完全に質問を誤解しました。 – SLaks

+0

実際に私はそれを得ました、あなたが正しく構文を使用する場合は動作します。コードサンプルが追加されました。 – Jaster

+0

完璧!これはサンプルコードで動作します。私は本番でそれを使用できることを願っています! ;-)ありがとうございました! – Palama

0

IManager <TIdentifier>が継承できない非一般的なIManagerは必要ありませんか?その後、IManager <IIdentifer>はIManagerであり、キャストできますか?

+0

IManagerが継承するジェネリック 'ISuperManager'が存在する場合は、どのように汎用プロパティContainerにアクセスできますか? – Palama

+0

必ずしもそうではありません。 IManager は、汎用ではない空のIManagerから継承できます。 IManager はIManagersです...と思います。 –

関連する問題