Допустим, мы хотим объявить
interface IPersonRepository : IRepository<Person> { }
Это потребовало бы, что существует общий интерфейс с одним параметром типа IRepository<EntityType>
.
interface IRepository<EntityType> where EntityType : Entity<KeyType>
{
EntityType Get(KeyType id);
}
В конце первой строки, вы имеете в виду то, что называется KeyType
, который не был заявлен ни определен. Нет типа «KeyType».
Это будет работать, хотя:
interface IRepository<EntityType> where EntityType : Entity<int>
{
EntityType Get(int id);
}
Или это:
interface IRepository<EntityType> where EntityType : Entity<string>
{
EntityType Get(string id);
}
Но вы не можете иметь оба противоречащих друг другу определений, в то же время, конечно. Очевидно, вас это не устраивает, потому что вы хотите определить свой интерфейс IRpository таким образом, чтобы он работал с другими типами ключей.
Ну, вы можете, если вы сделаете это родовое в типе ключа:
interface IRepository<KeyType, EntityType> where EntityType : Entity<KeyType>
{
EntityType Get(KeyType id);
}
Существует альтернативный подход:
interface IRepository<KeyType>
{
EntityType<KeyType> Get(KeyType id);
}
Теперь вы можете определить
class PersonRepository : IRepository<int>
{
public EntityType<int> Get(int id) { ... }
}
Очевидно, вы не были бы этому довольны, потому что вы хотели бы заявить, что метод Get должен вернуть Person
, а не только Entity<int>
.
Общий интерфейс с двумя параметрами типа в единственном решении. И действительно, между ними существует необходимая связь, выраженная в ограничении. Но здесь нет избыточности: указание int
для параметра типа не содержит достаточной информации.
Если мы говорим
class PersonRepository : IRepository<int, Person>
{
public Person Get(int id) { ... }
}
Существует действительно избыточность: определение параметра типа int
является избыточным, когда уже был указан параметр типа Person
.
Можно было бы получить op с синтаксисом, позволяющим вывести KeyType. Например, Патрик Хоффман предложил:
class PersonRepository : IRepository<EntityType: Person>.
{
public Person Get(int id) { ... }
}
Хотя теоретически возможно, я боюсь, что это добавит много сложностей в спецификации языка и компилятора, очень мало выгоды. На самом деле, есть ли вообще прибыль? Вы, конечно, не сохранили бы нажатия клавиш! Сравните эти два:
// current syntax
class PersonRepository : IRepository<int, Person>
{
public Person Get(int id) { ... }
}
// proposed syntax
class PersonRepository : IRepository<EntityType: Person>
{
public Person Get(int id) { ... }
}
Язык такой, какой он есть, и для меня это не выглядит слишком плохо.
Как он должен знать «KeyType»? Можете ли вы показать полный синтаксис того, что вы ожидаете? Последнее определение интерфейса выглядит неполным. –
Я не думаю, что это возможно. Компилятор недостаточно «умный». Я не стану отвечать, хотя, потому что «я не могу думать о том, как вы это делаете», недостаточно доказательств, которого вы не можете. – Falanwe
Я предполагаю, что последняя строка кода должна быть 'interface IPersonRepository: IRepository {...}' –
Rawling