Почему компилятор C # не может определить делегат универсального типа из сигнатуры функции? [Дубликат]

    

На этот вопрос уже есть ответ здесь:

    

Я работаю с функцией, которая принимает две функции в качестве параметров и возвращает новую составную:

public static Action<T> Compose<T>(Action<T> first, Action second)
{
    return new Action<T>(arg =>
    {
        first(arg);
        second();
    });
}

Я заметил, что компилятор жалуется, если я не указываю T при отправке ему статической функции или функции-члена (как в отличие от фактического объекта Action<T>):

static void Main(string[] args)
{
    // compiler error here
    var composed = Compose(Test, () => Console.WriteLine(" world"));
    composed("hello");

    Console.ReadLine();
}

public static void Test(string arg)
{
    Console.Write(arg);
}

Сообщение об ошибке:

  

Аргументы для метода 'ConsoleTest.Program.Compose (System.Action, System.Action)' не могут быть выведены из использования. Попробуйте указать аргументы типа явно.

Мой вопрос : почему здесь нельзя определить аргумент типа? Подпись Test известна во время компиляции, не так ли? Действительно ли есть какая-то функция, которую вы могли бы поставить вместо Test, которая бы делала его подпись неоднозначной?

Сноска: я знаю, что могу просто отправить new Action<string>(Test) вместо Test в Compose (как отмечено в этот вопрос ) - у меня вопрос" почему ", а не" как я могу это сделать ".

7 голосов | спросил McGarnagle 26 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 26 Sep 2013 01:11:34 +0400 2013, 01:11:34

2 ответа


0

Полагаю, это как-то связано с тем, что, по крайней мере, с точки зрения компилятора, Test на самом деле является методом group ', пока компилятор не определит, какие типы параметров он будет иметь. Это верно, даже если в группе есть только один метод (только один метод Test в текущей области видимости).

Заметим:

var composed = Compose<object>(Test, () => Console.WriteLine(" world"));

выдает ошибку:

  

Наилучшее совпадение перегруженного метода для 'Compose<object>(System.Action<object>, System.Action)' содержит недопустимые аргументы

     

Аргумент 1: невозможно преобразовать из 'группы методов' в 'System.Action<object>'

Но это нормально:

var composed = Compose<string>(Test, () => Console.WriteLine(" world"));

Я предполагаю, что компилятор видит как выражение группы методов (Test), так и неявно типизированный вызов универсального метода (Compose) как «несвязанный» в некотором смысле. Он не может полностью определить, какой метод выбрать из группы методов из подписи типа 'unbound' параметра для Compose, и он невозможно определить, какой параметр типа типа для Compose из подписи. Нужно, чтобы один или другой были «связаны», чтобы скомпилировать все утверждение.

ответил p.s.w.g 26 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 26 Sep 2013 01:27:56 +0400 2013, 01:27:56
0

Это может быть связано с ковариацией. Хотя тип аргумента Test известен, вы можете создать делегат более определенного типа.

public class BaseClass { }
public class DerivedClass : BaseClass { }

static class Program
{
    static void Main(string[] args)
    {
        var composed = Compose<DerivedClass>(Test, () => Console.WriteLine(" world"));
        composed(new DerivedClass());

        Console.ReadLine();
    }

    public static void Test(BaseClass arg)
    {
        Console.Write(arg);
    }
}
ответил Douglas 26 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 26 Sep 2013 01:33:08 +0400 2013, 01:33:08

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132