Контравариантные типы значений делегатов - PullRequest
7 голосов
/ 09 июня 2010

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

ниже не работает

private delegate Asset AssetDelegate(int m);

internal string DoMe()
{
    AssetDelegate aw = new AssetDelegate(DelegateMethod);
    aw(32);
    return "Class1";
}

private static House DelegateMethod(object m)
{
    return null;
}

Ответы [ 2 ]

5 голосов
/ 11 июня 2010

Проблема в том, что int не является объектом .

Int может быть в штучной упаковке для объекта.Результирующий объект (он же в штучной упаковке int), конечно, является объектом, но это уже не совсем int.

Обратите внимание, что " is ", который я использую выше, не являетсятакой же как оператор C # равен .Мое " is " означает "конвертируемое в неявное ссылочное преобразование ".Это значение « is », используемое, когда мы говорим о ковариантности и контравариантности.

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

House неявно конвертируется в Asset посредством преобразования ссылок.Нет необходимости создавать или изменять какие-либо объекты.

Рассмотрим пример ниже.Обе переменные house и asset ссылаются на один и тот же объект.Переменные integer и boxedInt, с другой стороны, содержат одно и то же значение, но они ссылаются на разные вещи.

House house = new House();
Asset asset = house;

int integer = 42;
object boxedInt = integer;

Boxing and Unboxing не так просто, как этоможет выглядеть такОн имеет много тонкостей и может неожиданно повлиять на ваш код.Смешивание бокса с ковариацией и контравариантностью - это простой способ поразить любого.

1 голос
/ 10 июня 2010

Я согласен с комментарием Энтони Пеграма - он основан на ссылочных типах, имеющих разную площадь памяти, чем типы значений: CLR может неявно использовать класс одного типа в качестве класса своего супертипа, но когда вы начинаете использовать значение типы, CLR нужно будет заключить ваше целое число, чтобы оно могло работать вместо объекта.

Если вы все равно хотите, чтобы это работало, у меня есть тенденция заключить объявление в выражение:

AssetDelegate aw = new AssetDelegate((m) => DelegateMethod(m));

Я не знаю, является ли это хорошей практикой или нет в плане синтаксиса, но помните, что бокс и распаковка стоят дорого.

...