いくつかのエンティティ インターフェイスを定義するクラス ライブラリがあるとします。
public interface ISomeEntity { /* ... */ }
public interface ISomeOtherEntity { /* ... */ }
このライブラリは、IRepository
インターフェースも定義します。
public interface IRepository<TEntity> { /* ... */ }
RepositorySourceBase
最後に、ライブラリには(以下を参照)と呼ばれる抽象クラスがあり、これをメイン プロジェクトで実装する必要があります。このクラスの目的は、基本クラスがRepository
実行時に新しいオブジェクトを取得できるようにすることです。特定のリポジトリが必要なため (この例ではISomeEntity
andのリポジトリ)、メソッドISomeOtherEntity
の汎用オーバーロードを記述しようとしています。GetNew<TEntity>()
次の実装はコンパイルされません ( GetNew()
where 句が異なっていても、2 番目のメソッドは "既に定義されている" というフラグが付けられます) が、私が達成しようとしていることに到達します。
public abstract class RepositorySourceBase // This doesn't work!
{
public abstract Repository<TEntity> GetNew<TEntity>()
where TEntity : SomeEntity;
public abstract Repository<TEntity> GetNew<TEntity>()
where TEntity : SomeOtherEntity;
}
このクラスの使用目的は次のようになります。
public class RepositorySourceTester
{
public RepositorySourceTester(RepositorySourceBase repositorySource)
{
var someRepository = repositorySource.GetNew<ISomeEntity>();
var someOtherRepository = repositorySource.GetNew<ISomeOtherEntity>();
}
}
一方、メイン プロジェクト (ライブラリ プロジェクトを参照する) には、 と の実装がISomeEntity
ありISomeOtherEntity
ます。
public class SomeEntity : ISomeEntity { /* ... */ }
public class SomeOtherEntity : ISomeOtherEntity { /* ... */ }
主なプロジェクトには、次の実装もありますIRepository<TEntity>
。
public class Repository<TEntity> : IRepository<TEntity>
{
public Repository(string message) { }
}
そして最も重要なことは、abstract の実装があることRepositorySourceBase
です。
public class RepositorySource : RepositorySourceBase
{
public override IRepository<ISomeEntity> GetNew()
{
return new (IRepository<ISomeEntity>)Repository<SomeEntity>(
"stuff only I know");
}
public override IRepository<ISomeOtherEntity> GetNew()
{
return new (IRepository<ISomeEntity>)Repository<SomeOtherEntity>(
"other stuff only I know");
}
}
と同様にRepositorySourceBase
、2 番目のGetNew()
メソッドには「定義済み」のフラグが立てられます。
つまり、C# は基本的に同じメソッドを繰り返していると考えています。なぜなら、メソッドとそのパラメーターだけを区別する方法がないからです。しかし、私の使用例を見るとGetNew()
、ジェネリック型と必要なメソッドを区別できるはずです。パラメータ、例:<ISomeEntity>
または<ISomeOtherEntity>
)。
これを機能させるにはどうすればよいですか?
アップデート
特定の名前のメソッドとFunc<T, TResult>
パラメーターを使用してこれを解決することになりました。
したがって、RepositorySourceBase
次のようになります。
public abstract class RepositorySourceBase
{
public abstract Repository<ISomeEntity> GetNewSomeEntity();
public abstract Repository<ISomeOtherEntity> GetNewSomeOtherEntity();
}
次RepositorySource
のようになります。
public class RepositorySource : RepositorySourceBase
{
public override IRepository<ISomeEntity> GetNewSomeEntity()
{
return new (IRepository<ISomeEntity>)Repository<SomeEntity>(
"stuff only I know");
}
public override IRepository<ISomeOtherEntity> GetNewSomeOtherEntity()
{
return new (IRepository<ISomeEntity>)Repository<SomeOtherEntity>(
"other stuff only I know");
}
}
さて、このすべてが始まったRepositoryUtilizer
のは、リポジトリのタイプ (ジェネリック型パラメーターとして指定できる) を知るだけで、ソースからリポジトリを取得できるジェネリック クラスが必要だったからです。結局のところ、それは不可能でした (または、少なくとも簡単には不可能でした)。ただし、デリゲートをパラメーターとして使用して、クラスがメソッド名を「知る」必要なしにリポジトリを取得できるようにすることが可能です。Func<T, TResult>
RepositoryUtilizer
次に例を示します。
public class RepositoryUtilizer
{
public DoSomethingWithRepository<TEntity>(
Func<TRepositorySource, IRepository<TEntity>> repositoryGetter)
{
using (var repository = repositoryGetter(RepositorySource))
{
return repository.DoSomething();
}
}
}
}