Преобразование из Func‹object,string› в Func‹string,string› работает, но в Func‹int,string› не работает

У меня есть следующий код:

static Func<object, string> s_objToString = (x) => x.ToString();
static Func<string, string> s_stringToString = s_objToString; //compiles
static Func<int, string> s_intToString = s_objToString; //error

Вторая строка компилируется, а третья не компилируется с ошибкой:

Невозможно неявно преобразовать тип "System.Func<object,string>" в "System.Func<int,string>"

Почему?

Я понимаю, что с генетикой, хотя строка происходит от объекта, а List<string> не происходит от List<object>, но здесь object до string работает, а object до int не работает, почему?

Хорошо, скажем, я понял, почему; теперь вопрос, есть ли способ обойти это (кроме определения класса MyInt для поля int, потому что работает Func<object,string> до Func<MyInt,string>)?


person Roey Nissim    schedule 23.10.2012    source источник
comment
Всегда стоит проверить предварительный просмотр на предмет вопроса, особенно когда вы задаете вопросы о дженериках (или о чем-то еще, что использует <> угловые скобки), чтобы убедиться, что ваш текст отображается или пометить его соответствующим образом.   -  person Damien_The_Unbeliever    schedule 23.10.2012
comment
@Roey Вы можете упаковать int, просто приведя его к object (или передав его s_objToString!), Для этого вам не нужен новый класс.   -  person Rawling    schedule 23.10.2012
comment
передача его в s_objToString или приведение к объекту может работать на простом решении. но моя проблема связана с такими функциями, как: public static string codeList<T>(List<T> thelist, Func<T, string> coder) подробнее см. новый вопрос   -  person Roey Nissim    schedule 23.10.2012


Ответы (2)


Это потому, что Func определяется как Func<in T, out TResult>, MSDN здесь, поэтому T является контравариантным с ключевым словом in, то есть вы можете использовать либо указанный вами тип, либо любой менее производный тип, но помните, что ковариантность и контравариантность не поддерживает тип значения:

Почему ковариация и контравариантность не поддерживают тип значения

Итак, для string работает, а для int не получается. Возможно, вам понадобится дополнительная информация о ковариантности и контравариантности:

http://msdn.microsoft.com/en-us/library/dd233060.aspx

http://msdn.microsoft.com/en-us/library/dd799517.aspx

person cuongle    schedule 23.10.2012
comment
Хорошо, спасибо. Есть ли способ обойти это? другое, чем определение класса MyInt для коробки int, приводит к тому, что Func‹object,string› работает с Func‹MyInt,string› - person Roey Nissim; 23.10.2012
comment
@RoeyNissim: Я бы сказал, что вы должны учитывать свой дизайн, чтобы избежать этого случая. Кстати, вы должны опубликовать здесь другой вопрос вместо вопроса об обновлении, чтобы задать другую проблему. - person cuongle; 23.10.2012

Потому что ко/противовариантность не работает для типов значений.

Пожалуйста, посмотрите здесь

Вариантность поддерживается только в том случае, если параметр типа является ссылочным типом. Вариантность не поддерживается для типов значений.
Следующее также не компилируется:

// int is a value type, so the code doesn't compile.
IEnumerable<Object> objects = new List<int>(); // Compiler error here.
person petro.sidlovskyy    schedule 23.10.2012
comment
непочтительно, следующее не компилируется со строкой: static List‹object› objs = new List‹string›(); - person Roey Nissim; 23.10.2012
comment
@RoeyNissim: концепция ковариантности и контравариантности работает только с универсальным интерфейсом и делегатом, поэтому List является инвариантным, а не ковариантным - person cuongle; 23.10.2012
comment
@RoeyNissim @CuongLe: этот ответ правильный, хотя здесь плохой пример List<int>. Ошибка компиляции в ответе возникает из-за неправильного приведения от IEnumerable<int> к IEnumerable<object> как таковому. - person Cheng Chen; 23.10.2012
comment
@DannyChen: да, это правильно, я просто попытался объяснить @RoeyNissim, почему List<object> objs = new List<string>() не работает - person cuongle; 23.10.2012