逆变委托值类型

发布于 2024-09-04 10:56:06 字数 304 浏览 5 评论 0 原文

谁能解释一下为什么逆变不适用于 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;
}

Can anyone shed light on why contravariance does not work with C# value types?

The below does not work

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

少女七分熟 2024-09-11 10:56:06

问题在于int 不是对象

int 可以装箱到一个对象。当然,结果对象(又名装箱 int)是一个对象,但它不再是一个 int 了。

请注意,我上面使用的“is”与 C# 运算符 。我的“”意思是“可以通过隐式引用转换进行转换”。这就是我们谈论协变和逆变时使用的“is”的含义。

int 可以隐式转换为对象,但这不是引用转换。它必须装箱。

House 可以通过引用转换隐式转换为 Asset。无需创建或修改任何对象。

考虑下面的例子。变量houseasset 都引用同一个对象。另一方面,变量integerboxedInt 拥有相同的值,但它们引用不同的东西。

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

int integer = 42;
object boxedInt = integer;

装箱和拆箱并不像看起来那么简单。它有许多微妙之处,可能会以意想不到的方式影响您的代码。将拳击与协变和逆变混合在一起是一种让任何人眼花缭乱的简单方法。

The problem is that an int is not an object.

An int can be boxed to an object. The resulting object (aka boxed int) is, of course, an object, but it's not exactly an int anymore.

Note that the "is" I'm using above is not the same as the C# operator is. My "is" means "is convertible to by implicit reference conversion". This is the meaning of "is" used when we talk about covariance and contravariance.

An int is implicit convertible to an object, but this is not a reference conversion. It has to be boxed.

An House is implicit convertible to an Asset through a reference conversion. There's no need to create or modify any objects.

Consider the example below. Both variables house and asset are referencing the very same object. The variables integer and boxedInt, on the other hand, hold the same value, but they reference different things.

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

int integer = 42;
object boxedInt = integer;

Boxing and Unboxing is not as simple as it may look like. It has many subtleties, and might affect your code in unexpected ways. Mixing boxing with covariance and contravariance is an easy way to make anyone dazzle.

笛声青案梦长安 2024-09-11 10:56:06

我同意 Anthony Pegram 的评论 - 它基于与值类型相比具有不同内存占用的引用类型:CLR 可以隐式使用一种类型的类作为其超类型的类,但是当您开始使用值类型时, CLR 需要对整数进行装箱,以便它可以在对象的位置工作。

如果你想让它工作,我倾向于将声明包装在一个表达式中:

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

我不知道这是否是一个好的做法,就语法而言,但请记住,装箱和拆箱是昂贵的。

I agree with Anthony Pegram's comment - it is based on reference types having a different memory footprint than the value types: the CLR can implicitly use a class of one type as a class of its super type, but when you start using value types, the CLR will need to box your integer so it can work in the place of the object.

If you're looking to make it work anyway, I have a tendency to wrap the declaration in an expression:

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

I don't know if that's good practice or not as far as syntax goes, but remember that boxing and unboxing is expensive.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文