Здесь ковариация / контравариантность может пригодиться. Эта функция позволяет вам определять входные / выходные теги на ваших шаблонах и делать следующее:
public interface IThing<out T> where T : IEnumerable<int> {
T Collection { get; }
}
public class Thing : IThing<int[]> {
public int[] Collection { get; set; }
}
Тогда это позволит вам определить другие реализации, а затем по-прежнему использовать их вместе как IThing<IEnumerable<int>>
s.
public class Thing2 : IThing<List<int>> {
public List<int> Collection { get; set; }
}
class Program {
static void Main() {
var x = new Thing();
var y = new Thing2();
new List<IThing<IEnumerable<int>>> { x, y };
}
}
Преимущество этого подхода перед явной реализацией интерфейса состоит в том, что вы гарантируете , что IThing.Collection является точно таким же методом, что и Thing.Collection, тогда как в явной реализации они на самом деле являются разными методами, поэтому нет такой гарантии. Недостатком, конечно, является то, что вам нужно быть немного более явным, и это делает код немного «шумнее», чтобы на него смотреть.
Не уверен, почему компилятор C # не мог понять это неявно; я предполагаю, что это займет слишком много времени, чтобы скомпилировать эту дополнительную проверку.