Объркан съм защо този C# код се компилира, докато подобен код не го прави

Нека вземем следния метод за разширение:

static class Extensions
{
   public static bool In<T>(this T t, params T[] values)
   {
      return false;
   }
}

Любопитен съм защо този код се компилира и изпълнява:

var x = new Object();
IEnumerable<int> p = new List<int> { 1, 2, 3 };
var t2 = x.In(p);

В рамките на In, values е Object[], сякаш List<int> се преобразува в движение в масив. За мен изглежда, че params T[] не съвпада с IEnumerable<int>, поради което съм изненадан, че това дори работи.

Сега този код:

var x = 5;
IEnumerable<int> p = new List<int> { 1, 2, 3 };
var t2 = x.In(p);

Не се изпълнява и генерира грешка на компилатора:

Грешка 2 Аргумент 2: не може да се преобразува от „System.Collections.Generic.IEnumerable“ в „int[]“

Това всъщност бих очаквал от първия. Може ли някой да обясни какво става тук? Благодаря!


person Mike Christensen    schedule 04.03.2014    source източник
comment
Питате ли защо първият се компилира или защо вторият не?   -  person SLaks    schedule 04.03.2014
comment
@SLaks - Най-вече се чудех защо първият се компилира, но вашият отговор го закова идеално.   -  person Mike Christensen    schedule 04.03.2014
comment
След това трябва да промените заглавието си. :)   -  person SLaks    schedule 04.03.2014


Отговори (1)


Изводът за тип преобразува първото ви повикване в

In<object>(x, p);

Параметрите на този затворен общ метод са object, params object[].
Следователно предаването на p имплицитно го преобразува в object, което става единственият елемент в масива params.

Вашето второ повикване се извежда (поради първия параметър) на

In<int>(x, p);

Тук вторият параметър може да бъде int[] (директно предаване на масив) или поредица от ints (чрез params).
Тъй като IEnumerable<int> не е нито едно от двете, получавате грешка.

person SLaks    schedule 04.03.2014
comment
да! Напълно пропуснах факта, че values беше масив от 1 елемент, а не от 3, когато отстранявах грешки, тъй като задържането на курсора на мишката върху него автоматично разширява стойностите. Ако бях видял това, щях да го получа веднага! - person Mike Christensen; 04.03.2014
comment
@MikeChristensen Е, аз обясних, че сте вие ​​по-рано... Разбира се, обясних го с код, а не с думи. - person Servy; 04.03.2014
comment
@MikeChristensen Не гласувах против вашия въпрос. Не е много зряло да се правят подобни предположения. Що се отнася до яснотата, предположих, че ще можете да разберете последиците, като знаете, че IEnumerable е обвит в масив, както казахте, че бихте могли. - person Servy; 04.03.2014
comment
@MikeChristensen: Добре сега, след като разбирате отговора на SLaks, проверете знанията си. Имате M(object) и M(params object[]). Обаждате се на M(null); Има четири възможности. (1) грешка, (2) първи метод (3) втори метод с нулев масив (4) втори метод с масив от един елемент, чийто единствен елемент е нулев. коя е тя - person Eric Lippert; 05.03.2014
comment
@EricLippert: За да бъда честен, това е повече за приоритетите в разрешаването на претоварване, което не съм обсъждал. - person SLaks; 05.03.2014
comment
@EricLippert - Да, съгласен съм със SLaks, изглежда е приоритетен проблем за разрешаване на претоварване. Току-що пробвах и изглежда, че в този случай се извиква M(params object[]), като стойността е null (Опция #3). Това, разбира се, повдига въпроса дали е възможно или не да се разясни това обаждане. - person Mike Christensen; 05.03.2014
comment
@MikeChristensen: Използвайте актьорски състав. - person SLaks; 05.03.2014
comment
@SLaks - Какво знаете, 1.In((Object)null); ще се държи като опция #1. - person Mike Christensen; 05.03.2014