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 に使用するパラメーターの制約は問題ではないようです。メソッド呼び出しが基本クラスにフォールスルーすることはありません。

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

考え?

4

2 に答える 2

3

このコードは、次の単純な例がコンパイルされないのと同じ理由でコンパイルされません。

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

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

メソッドは単に同じ署名を持っていません。はい、呼び出すことができsomeBar.Foo(5)、それは に解決Tされますが、 in には実際に をパラメーターとして受け取るメソッドと同じ署名がまだないintという事実が残っています。FooBarint

型に非ジェネリック メソッドとジェネリック メソッドの両方を含めることで、これをさらに実証できます。これにより、あいまいさに関連するエラーは発生しません。

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が、最終的にはすべての呼び出しが引き続きジェネリック バージョンに向けられます。

于 2012-10-29T17:12:16.147 に答える
1

コンパイラは何TKeyが入っているかを認識せず、BaseRepositoryこれを関連付けるIRetreivable方法もありません (ジェネリック メソッドは非ジェネリック メソッドと同じシグネチャを持たないことに注意してください)。

これらの線に沿って、基本クラスがインターフェイスの継承を行い、次のように指定することも必要だと思います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;
    }
}
于 2012-10-29T17:06:28.683 に答える