Компилятор не может определить универсальные типы при передаче метода - PullRequest
11 голосов
/ 08 апреля 2011

У меня проблемы с C # и выводом универсального типа.Я хочу написать метод, который получает метод любого типа, но компилятор не может определить типы методов, которые я передаю. Компилятор всегда жалуется на сообщение

Ожидается метод с '???TestFunc (???, ???) 'signature

Вот тестовый пример.

using System;

public class Example
{
    private interface ITest
    {
        int TestFunc(string str, int i);
    }

    private class Test : ITest
    {
        public int TestFunc(string str, int i) { return 0; }
    }

    public static void Main()
    {
        ITest t = new Test();
        DoWork(t.TestFunc);
    }

    public static void DoWork<T1, T2, TResult>(Func<T1, T2, TResult> func)
    {
    }
}

Может кто-нибудь объяснить мне, в чем проблема?

Ответы [ 2 ]

3 голосов
/ 09 апреля 2011

Правила вывода типов ужасно сложны, к сожалению. По крайней мере, я нахожу их сложными, и я полагаю, что Эрик и Мэдс предпринимают еще одну попытку упростить их для следующей версии спецификации - вполне возможно, не меняя то, что реализовано, а меняя то, как это выражено в спецификации.

В этом случае фундаментальная проблема заключается в том, что типы групп методов не способствуют выводу типов, даже если тип return делает это. В частности, из 7.5.2.6 спецификации C # 4:

В противном случае, если E - это группа методов, а T - тип делегата или тип дерева выражений с типами параметров T1… Tk и типом возврата Tb, а разрешение перегрузки E с типами T1… Tk приводит к единственному методу с типом возврата U, то нижний предел делается из U в Tb.

Это относится к типам возвращаемых данных, но не указывает ничего о типах параметров. Единственный соответствующий бит спецификации, который я могу найти о типах параметров для групп методов, это:

Если E является группой методов или неявно типизированной анонимной функцией, а T является типом делегата или типом дерева выражений, то все типы параметров T являются входными типами E с типом T.

К сожалению, это не поможет исправить границы.

Так что в основном это работает:

с использованием системы;

public class Example
{
    private interface ITest
    {
        int TestFunc();
        int TestFunc2(string value);
    }

    public static void Main()
    {
        ITest t = null;
        DoWork(t.TestFunc);
        DoWork2(t.TestFunc2);
    }

    public static void DoWork<TResult>(Func<TResult> func)
    {
    }

    public static void DoWork2<TResult>(Func<string, TResult> func)
    {
    }
}

... потому что единственным параметром типа, который должен быть выведен в любом случае, является тип возвращаемого значения. Когда вы пытаетесь определить параметры типа на основе входных параметров метода, что-то идет не так: (

1 голос
/ 08 апреля 2011

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

    private class Test 
    {
        public int TestFunc(string str, int i) { return 0; }
        public int TestFunc(string str, long i) { return 0; }
    }

    public static void Main()
    {
        Test t = new Test();
        DoWork(t.TestFunc);
    }

    public static void DoWork<T1, T2, TResult>(Func<T1, T2, TResult> func)
    {
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...