Вынудить компилятор C # использовать перегрузку неуниверсального метода с параметром выражения Linq - PullRequest
0 голосов
/ 27 декабря 2018

У меня перегружены методы, один универсальный и один неуниверсальный.Оба метода получают выражение Linq как один параметр:

public void Test(Expression<Action<char>> expr) {}

public void Test<T>(Expression<Func<char, T>> expr) {}

Теперь рассмотрим следующий вызов:

var sb = new StringBuilder();
Test(c => sb.Append(c));

Компилятор выберет универсальный метод, поскольку метод Append() делает(к сожалению) вернуть StringBuilder.Тем не менее, в моем случае мне абсолютно необходимо вызвать неуниверсальный метод.

Следующий обходной путь показывает, что в коде нет проблем с типами (неуниверсальный вызов будет вполне допустимым):

Expression<Action<char>> expr = c => sb.Append(c);
Test(expr);

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

Вы можете поиграть с этим на SharpLab.io .

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Вы можете использовать пустой метод, чтобы проглотить возвращаемое значение sb.Append.Я бы не назвал это обходным путем, поскольку он просто заставляет компилятор работать нормально, но он не совсем чистый и симпатичный.

static public void NoValue(object value) {}

static public void Test(Expression<Action<char>> action) 
{
    Console.WriteLine("Test()");
}

static public void Test<T>(Expression<Func<char, T>> func) 
{
    Console.WriteLine("Test<T>()");
}

Когда вы переносите вывод в NoValue, компилятор правильно видит это как действие, а не функцию.

static public void Main()
{
    var sb = new StringBuilder();
    Test(c => NoValue(sb.Append(c)) );
    Test(c => sb.Append(c) );
}

Вывод:

Test()
Test<T>()
0 голосов
/ 27 декабря 2018

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

static public void Test(Expression<Action<char>> action) 
{
    Console.WriteLine("Test()");
}

static public void Test<T>(Expression<Func<char, T>> func) 
{
    Console.WriteLine("Test<T>()");
}

Если вам нужна неуниверсальная версия, просто укажите имя параметра action: в списке аргументов.

static public void Main()
{
    var sb = new StringBuilder();
    Test(action: c => sb.Append(c) );
    Test(func: c => sb.Append(c) );
}

Вывод:

Test()
Test<T>()

Это может быть проще в использовании, чем выписывание приведенного выражения.

Fiddle

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...