Скажем, у меня есть библиотека классов, которая определяет несколько сущностей интерфейса:Проблем с абстрактными обобщенными методами
public interface ISomeEntity { /* ... */ }
public interface ISomeOtherEntity { /* ... */ }
Эта библиотека также определяет IRepository
интерфейса:
public interface IRepository<TEntity> { /* ... */ }
И, наконец, библиотека имеет абстрактный класс под названием RepositorySourceBase
(см. ниже), который должен реализовать основной проект. Цель этого класса - позволить базовому классу захватывать новые объекты Repository
во время выполнения. Поскольку необходимы определенные репозитории (в этом примере репозиторий для ISomeEntity
и ISomeOtherEntity
), я пытаюсь написать общие перегрузки метода GetNew<TEntity>()
.
Следующая реализация не компилирует (второй GetNew()
метод помечается как «уже определен», даже несмотря на то, где положение отличается), но он получает на то, что я пытаюсь выполнить:
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) { }
}
И самое главное, он имеет реализацию абстрактного 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
, второй метод GetNew()
получает помечены как «уже определенные».
Так, C# в основном думает, что я повторять тот же самый метод, потому что нет никакого способа отличить методы от своих параметров только, но если вы посмотрите на мой пример использования, кажется, что я должен быть в состоянии чтобы отличить то, что GetNew()
Я хочу от параметра типового типа, например, <ISomeEntity>
или <ISomeOtherEntity>
).
Что нужно сделать, чтобы заставить это работать?
Update
Я в конечном итоге решить это с помощью специально названные методы и параметр 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
класс, который мог захватите репозиторий из источника, просто зная тип репозитория (который может быть указан как параметр типового типа). Оказывается, это было невозможно (или, по крайней мере, нелегко). Однако то, что is возможно использовать делегат Func<T, TResult>
в качестве параметра, чтобы позволить классу RepositoryUtilizer
получить репозиторий без необходимости «знать» имя метода.
Вот пример:
public class RepositoryUtilizer
{
public DoSomethingWithRepository<TEntity>(
Func<TRepositorySource, IRepository<TEntity>> repositoryGetter)
{
using (var repository = repositoryGetter(RepositorySource))
{
return repository.DoSomething();
}
}
}
}
+1. Спасибо за ваш ответ и за ссылку, Эрик.Мне удалось добиться результата, который я искал, используя специально названные методы (как вы предлагаете) и параметр «Func», который позволяет мне использовать лямбда-выражения для получения репозитория из источника. Не совсем так красиво, как просто быть в состоянии указать тип, который я хочу, но он в основном выполняет степень «родословности», которую я искал :) – devuxer