2012-10-29 7 views
6

サンプルプログラムは:このジェネリックスの動作について説明し、回避策がある場合はこれを説明できますか?以下

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace GenericsTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      IRetrievable<int, User> repo = new FakeRepository(); 

      Console.WriteLine(repo.Retrieve(35)); 
     } 
    } 

    class User 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
    } 

    class FakeRepository : BaseRepository<User>, ICreatable<User>, IDeletable<User>, IRetrievable<int, User> 
    { 
     // why do I have to implement this here, instead of letting the 
     // TKey generics implementation in the baseclass handle it? 
     //public User Retrieve(int input) 
     //{ 
     // throw new NotImplementedException(); 
     //} 
    } 

    class BaseRepository<TPoco> where TPoco : class,new() 
    { 
     public virtual TPoco Create() 
     { 
      return new TPoco(); 
     } 

     public virtual bool Delete(TPoco item) 
     { 
      return true; 
     } 

     public virtual TPoco Retrieve<TKey>(TKey input) 
     { 
      return null; 
     } 
    } 

    interface ICreatable<TPoco> { TPoco Create(); } 
    interface IDeletable<TPoco> { bool Delete(TPoco item); } 
    interface IRetrievable<TKey, TPoco> { TPoco Retrieve(TKey input); } 
} 

このサンプル・プログラムでは、私の実際のプログラムが使用するインターフェースを表し、(FakeRepositoryでコメントアウト)私がいる問題を示しています。このメソッド呼び出しは、基本クラス(実際の例では95%を扱うことができる)によって一般的に処理され、TKeyの型を明示的に指定することで子クラスのオーバーライドが可能です。 IRetrievableにどのようなパラメータ制約が使用されているかは重要ではないようですが、基本クラスに渡るメソッド呼び出しを決して得ることはできません。

また、誰かがこの種の動作を実装して、私が最終的に探している結果を得る別の方法を見ることができれば、私はそれを見ることに非常に興味があります。

思考?

答えて

3

コードは同じ理由で、この単純な例をコンパイルしていないこと

public interface IBar 
{ 
    void Foo(int i); 
} 

public class Bar : IBar 
{ 
    public void Foo<T>(T i) 
    { 
    } 
} 

これらのメソッドは単純に同じシグネチャを持っていません。はい、あなたはsomeBar.Foo(5)と呼ぶことができ、それはTintに解決しますが、実際にintをパラメータとして受け取る方法と同じ署名がまだBarに存在しないという事実は、Fooに残ります。

さらに、このタイプに非ジェネリックと汎用の両方のメソッドを持たせることで、これを実証できます。これは曖昧関連のエラーにはなりません。

public class Bar : IBar 
{ 
    public void Foo(int i) 
    { 

    } 
    public void Foo<T>(T i) 
    { 
    } 
} 

実際にあなたの問題を解決するためとして、あなたがこれを行うことができます:

class FakeRepository : BaseRepository<User>, ICreatable<User>, IDeletable<User>, IRetrievable<int, User> 
{ 
    public User Retrieve(int input) 
    { 
     return Retrieve<int>(input); 
    } 
} 

これはFakeRespositoryを持っていることを意味します両方のジェネリックと非ジェネリックバージョンRetrieveですが、結局すべてのコールは引き続きジェネリックバージョンに転送されます。

1

コンパイラはBaseRepositoryにあり、IRetreivableにこれを関連する方法がありませんどのようなTKeyないアイデアを持っていない(一般的な方法は、非ジェネリックのものと同じシグネチャを持っていないことに注意)。

私は、基本クラスを継承するインタフェースをやって、あなたはこれらの線に沿ってより多くの何かをしたいと思うし、またTKeyを指定するには:

class FakeRepository : BaseRepository<int, User> 
{ 
} 

class BaseRepository<TKey, TPoco> : ICreatable<TPoco>, IDeletable<TPoco>, IRetrievable<TKey, TPoco> where TPoco : class,new() 
{ 
    public virtual TPoco Create() 
    { 
     return new TPoco(); 
    } 

    public virtual bool Delete(TPoco item) 
    { 
     return true; 
    } 

    public virtual TPoco Retrieve<TKey>(TKey input) 
    { 
     return null; 
    } 
} 
+0

残念ながら私は元の例にこれを含めていませんでした。私のFakeRepositoryはいくつかのIRetrievableインターフェースを持っていて、すべて同じTPocoであるがTKeyは異なっています。 –

関連する問題