Как применить универсальное расширение к определенному универсальному типу? - PullRequest
1 голос
/ 28 декабря 2011

Представьте, что у меня есть метод расширения, который работает с интерфейсом абстрактных объектов:

public static void BlowTheirWhoHoovers(this ICollection<Image> source)
{
   ...
}

Это расширение знает, как создать список пользователей в списке изображений.

Примечание

  • это список изображений , который является абстрактным. До тех пор, пока списки содержат все, что происходит от Image (например, Bitmap, Metafile, PngImage), расширение может обрабатывать это
  • source список может быть любым списком, если он предоставляет ICollection
  • , поскольку в списке source потенциально могут быть добавлены или удалены элементы, это ICollection, а не IEnumeration (IEnumeration не поддерживает изменение списка)

Это все хорошо, кроме того, что не работает, метод расширения не найден:

Collection<Bitmap> whoHonkers = new Collection<Bitmap>();
whoHonkers.BlowTheirWhoHoovers();

enter image description here

Я предполагаю, что это не удалось, потому что:

  • Visual Studio не думает, Collection реализует ICollection<T>
  • Visual Studio не думает Bitmap происходит от Image

Теперь я могу изменить мой добавочный номер:

public static void BlowTheirWhoHoovers(this Collection<Bitmap> source)
{
   ...
}

который компилирует :

enter image description here

за исключением того, что он больше не полезен (для него требуется Collection и требуется Bitmap), например он не работает ни на чем, кроме Collection<T>:

List<Bitmap> whoHonkers = new List<Bitmap>();
whoHonkers.BlowTheirWhoHoovers();

Он также не работает на всем, что Bitmap:

List<Metafile> whoHonkers = new List<Metafile>();
whoHonkers.BlowTheirWhoHoovers();

или

List<PngImage> whoHonkers = new List<PngImage>();
whoHonkers.BlowTheirWhoHoovers();

Как применить расширение ко всему, что равно :

ICollection<Image>

я не могу заставить кого-либо изменить свою декларацию, например ::1010 *

List<Bitmap>

до

Collection<Image>

Обновление

Возможные пути исследования решения:

  • поиск синтаксиса, разрешающего расширения для вещей, которые компилятор должен уметь
  • приведение списка вручную; выполняет за это работу компилятора

Обновление # 2

Я мог бы упростить некоторые отвлекающие факторы вокруг ICollection и сделать это IEnumerable (так как это гипотетический пример, я могу составить все, что захочу). Но скриншоты уже показывают Collection, поэтому я собираюсь оставить все как есть.

Обновление № 3 :

Как указал foson , изменение его на IEnumerable позволяет обмануть ответ. Так что это определенно должно остаться как ICollection.

1 Ответ

1 голос
/ 28 декабря 2011

Похоже на ковариантную проблему.

Если вы измените подпись на

public static void BlowTheirWhoHoovers(this IEnumerable<Image> source)

Вы должны быть в состоянии сделать это в .NET 4 (не SL).

Проблема с разницей в том, что если вы передадите в метод ICollection<JpegImage>, сам метод не будет знать, что он может добавлять только JpegImage s, а не Bitmap s, что побеждает безопасность типов. Поэтому компилятор не позволяет вам сделать это. Параметр типа IEnumerable является ковариантным, как видно из ключевого слова out, а параметр типа ICollection - нет (поскольку он находится как в позициях возврата, так и в позициях параметров метода в интерфейсе ICollection)

public interface IEnumerable<out T>

http://msdn.microsoft.com/en-us/library/dd799517.aspx

...