Ограничение разрешения статического расширения для самой узкой совпадающей подписи - PullRequest
0 голосов
/ 23 декабря 2019

У меня есть два статических метода расширения, которые похожи в том, что один принимает IEnumerable, а другой просто T. Каждый из них возвращает ExpandoObject, и у меня есть два для целей оптимизации, так как я использую Reflection внутри каждого.

Здесьмои сигнатуры методов:

public static ExpandoObject DoSomething<TSource>(this TSource source, string somethingElse)

public static ExpandoObject DoSomething<TSource>(this IEnumerable<TSource> source, string somethingElse)

Сначала я написал последний, а затем выписал тестовый модуль, чтобы проверить его, он прошел. Затем я написал прежнее расширение, и теперь мой модульный тест с IEnumerable терпит неудачу, потому что он соответствует TSource (как список), а не соответствует сигнатуре IEnumerable.

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

1) IsЕсть ли способ заставить его выбрать более узкое соответствие или иным образом выбрать, какое расширение я хочу использовать? 2) В качестве альтернативы, есть ли способ защитить типы, переданные для защиты реализации TSource, от получения любых типов IEnumerable?

Редактировать : Продолжая играть с этим, я все еще в замешательствеотносительно того, как компилятор выбирает соответствующее расширение для использования.

Если я сообщаю тип вывода вместо использования var, как показано ниже, он все равно выбирает объектный подход и возвращает только один ExpandoObject вместо IEnumerable из них:

IEnumerable<MyObj> data = new List<MyObj>(); var results = results.DoSomething("");

Это правильно отобразит расширение, которое возвращает IEnumerable, но если я сделаю следующее:

var data = new List<MyObj>(); var results = results.DoSomething("");

Компилятор выберетВместо этого объектно-ориентированный подход возвратит один ExpandoObject.

Учитывая, что List реализует IEnumerable, почему компилятор выбирает сопоставление с объектом для определения соответствующего расширения вместо выбора версии IEnumerable, если я не приведу явное приведениепеременная для ввода как IEnumerable?

Итак, вопрос № 3: что информирует компилятор о том, какой из них использовать? Он явно выберет самый узкий из доступных вариантов, если это явное совпадение типов, но почему он сразу же прибегает к самому широкому методу, даже если доступно более узкое совпадение (например, ввод списка)?

1 Ответ

1 голос
/ 23 декабря 2019

Компилятору не имеет смысла выводить, какая функция будет правильной в этом случае (список по-прежнему является объектом), поэтому он использует ту, которая соответствует всем случаям.

Простейший путь впереддолжен иметь одну функцию, которая обрабатывает оба случая.

public static object DoSomething<TSource>(this TSource source, string somethingElse)
{
    if (source is System.Collections.IEnumerable)
    {
        Console.WriteLine("List");
    }
    else
    {
        Console.WriteLine("Instance");
    }
    return null;
}
...