Кто-либо может пролить свет на то, почему контравариантность не работает с типами значения 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;
}
Проблема в том, что int не является объектом .
Целое число может быть помещено в объект. Результирующий объект (также известный как int в рамке), конечно, является объектом, но это уже не совсем int.
Обратите внимание, что выражение « равно », которое я использую выше, не то же самое, что оператор C # - . Мое выражение « is » означает, что «можно преобразовать в неявное преобразование ссылки ». Это значение выражения « is » используется, когда мы говорим о ковариации и контравариантности.
Тип int неявно преобразуется в объект, но это не ссылочное преобразование. Это должно быть упаковано в коробку.
Дом
неявно преобразуется в Актив
посредством преобразования ссылки. Нет необходимости создавать или изменять какие-либо объекты.
Рассмотрим пример ниже. Обе переменные house
и asset
ссылаются на один и тот же объект. Переменные integer
и boxedInt
, с другой стороны, имеют одно и то же значение, но ссылаются на разные вещи.
House house = new House();
Asset asset = house;
int integer = 42;
object boxedInt = integer;
Упаковка и распаковка не так проста, как может показаться. Он имеет множество тонкостей и может неожиданным образом повлиять на ваш код. Смешивание бокса с ковариацией и контравариантностью - простой способ поразить любого.
Я согласен с комментарием Энтони Пеграма - он основан на ссылочных типах, имеющих другой объем памяти, чем типы значений: CLR может неявно использовать класс одного типа как класс своего супертипа, но когда вы начинаете использовать значение типов, CLR нужно будет поместить ваше целое число в ящик, чтобы оно могло работать вместо объекта.
Если вы все равно хотите, чтобы это работало, у меня есть тенденция заключать объявление в выражение:
AssetDelegate aw = new AssetDelegate((m) => DelegateMethod(m));
Я не знаю, является ли это хорошей практикой или нет с точки зрения синтаксиса, но помните, что бокс и распаковка стоит дорого.