Перегрузка, вывод универсального типа и ключевое слово 'params'
-
10-07-2019 - |
Вопрос
Я только что заметил странное поведение с разрешением перегрузки.
Предположим, что у меня есть следующий метод :
public static void DoSomething<T>(IEnumerable<T> items)
{
// Whatever
// For debugging
Console.WriteLine("DoSomething<T>(IEnumerable<T> items)");
}
Теперь я знаю, что этот метод часто будет вызываться с небольшим количеством явных аргументов, поэтому для удобства я добавляю эту перегрузку :
public static void DoSomething<T>(params T[] items)
{
// Whatever
// For debugging
Console.WriteLine("DoSomething<T>(params T[] items)");
}
Теперь я пытаюсь вызвать эти методы :
var items = new List<string> { "foo", "bar" };
DoSomething(items);
DoSomething("foo", "bar");
Но в обоих случаях перегрузка с params
называется.Я бы ожидал, что IEnumerable<T>
перегрузка, вызываемая в случае List<T>
, потому что это кажется лучшим совпадением (по крайней мере, мне).
Является ли такое поведение нормальным ?Кто - нибудь может это объяснить ?Я не смог найти никакой четкой информации об этом в документах MSDN...Какие правила разрешения перегрузки здесь задействованы ?
Решение
Здесь уместен раздел 7.4.3 спецификации C # 3.0.По сути, массив параметров расширен, поэтому вы сравниваете:
public static void DoSomething<T>(T item)
и
public static void DoSomething<T>(IEnumerable<T> item)
Тот Самый T
предполагается, что первое совпадение будет List<string>
и тот T
предполагается, что второе совпадение будет string
.
Теперь рассмотрим преобразования, необходимые для преобразования аргумента в тип параметра - в первом случае это List<string>
Для List<string>
;во втором случае это List<string>
Для IEnumerable<string>
.Первое преобразование является лучшим, чем второе, в соответствии с правилами, изложенными в разделе 7.4.3.4.
Парадоксальный бит - это вывод типа.Если вы исключите это из уравнения, оно будет работать так, как вы ожидаете:
var items = new List<string> { "foo", "bar" };
DoSomething<string>(items);
DoSomething<string>("foo", "bar");
На этом этапе в каждом вызове есть только один применимый член функции.