2014-02-13 2 views
2

Когда я запускаю эту программу я получаю две ошибки в строке, содержащей п (3,4)C# Func <> преобразование делегата аргумент ошибки

Аргумент 1: не удается преобразовать из «Int» в T

Аргумент 2: невозможно преобразовать из 'int' в T

Я думал, что тип T будет int, как указано лямбдой. Но если это так, то почему ошибки преобразования? Я что-то не понимаю?

class Program 
{ 
    static void DoStuff<T>(Func<T, T, T> fn) 
    { 
     Console.WriteLine(fn(3, 4)); 
    } 

    static void Main() 
    { 
     DoStuff((int x, int y) => x + y); 
    } 
} 

Это работает, если изменить параметры, чтобы принять Интс в качестве аргументов:

class Program 
{ 
    static void DoStuff<T>(T x, T y, Func<T, T, T> fn) 
    { 
     Console.WriteLine(fn(x, y)); 
    } 

    static void Main() 
    { 
     DoStuff(3, 4, (int x, int y) => x + y); 
    } 
} 

Я родом из C++ фона, таким образом пытаясь получить мою голову вокруг того, что работает, а что нет в C#

+1

Это недопустимо, потому что для чего-то вроде 'DoStuff ' оно недействительно.Дженерики не работают, как шаблоны C++, если это то, о чем вы думали. – hvd

ответ

8

Внутри метода DoStuff<T>, фактический тип T неизвестна; Ваш код передает int S функции, при условии, что T является int, но T может быть на самом деле ничего, как string, так что вы бы проездом int сек на функцию, которая принимает только string с.


RE «Я родом из C++ фона, таким образом пытаясь получить мою голову вокруг того, что работает, а что не в C#»:

C# дженериков похожи на шаблоны C++, но они на самом деле совсем другое.

  • В C++ шаблоны создаются при компиляции во время использования; если вы используете метод шаблона с 3 различными типами для T, компилятор будет генерировать 3 разных метода. Тело шаблона не должно быть действительным для любого T, если оно действительно для фактических случаев использования. (извините, если мои объяснения не совсем точны, я не очень хорошо знаю C++)

  • В C# нет поколений во время компиляции, основанных на использовании; компилятор генерирует только 1 общий метод, и фактический метод времени выполнения для заданного T генерируется средой выполнения. Чтобы это сработало, компилятор C# должен убедиться, что тело метода будет действительным для любого T (или если вы указали ограничения для T, любого T, который соответствует ограничениям). Вот почему вы получаете ошибку в своем первом фрагменте: тело общего метода будет действительным только в том случае, если T были int.

Я предлагаю вам прочитать ответы на this question для более подробного объяснения.

+0

Спасибо. Я отредактировал свое сообщение, чтобы показать рабочий фрагмент ... можете ли вы объяснить, почему это работает? – PowerApp101

+0

@ 20thCenturyBoy, который работает, поскольку указаны аргументы, является сайтом вызова, где известен фактический тип 'T'. –

+0

@ 20thCenturyBoy, я обновил свой ответ, чтобы объяснить разницу между шаблонами C++ и генераторами C# –

1

Не нужно использовать дженерики здесь. Изменение

static void DoStuff<T>(Func<T, T, T> fn) 

в

static void DoStuff(Func<int, int, int> fn) 
+0

Да, я знаю, что это работает, но я хотел понять, почему общая версия не может вывести тип T как int. – PowerApp101

+0

@ 20thCenturyBoy Поскольку вывод типового типа происходит на сайте вызова, а не в определении метода. Было бы бессмысленно выводить типы параметров при определении метода, потому что тогда метод не был бы общим в первую очередь. – Kyle

+0

@Kyle Я понимаю, что вы имеете в виду. Я просто подумал, что информация о типе, содержащаяся в лямбде на сайте вызова, будет достаточной для вывода типа T, то есть lambda указывает ints. – PowerApp101

Смежные вопросы