为什么直接铸造失败,但“as”运算符在测试受限泛型类型时是否成功? [英] Why does a direct cast fail but the "as" operator succeed when testing a constrained generic type?

查看:146
本文介绍了为什么直接铸造失败,但“as”运算符在测试受限泛型类型时是否成功?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当编译一些使用类型约束的泛型的C#代码时,我遇到了一个有趣的好奇心。我写了一个快速测试用例来说明。我在Visual Studio 2010中使用.NET 4.0。

``I've run across an interesting curiosity when compiling some C# code that uses generics with type constraints. I've written a quick test case for illustration. I'm using .NET 4.0 with Visual Studio 2010.

namespace TestCast
{
    public class Fruit { }

    public class Apple : Fruit { }

    public static class Test
    {
        public static void TestFruit<FruitType>(FruitType fruit) 
            where FruitType : Fruit
        {
            if (fruit is Apple)
            {
                Apple apple = (Apple)fruit;
            }
        }
    }
}

强制转换为Apple失败,并显示错误:无法将类型'FruitType'转换为'TestCast.Apple'。但是,如果我更改行以使用作为运算符,它编译没有错误:

The cast to Apple fails with the error: "Cannot convert type 'FruitType' to 'TestCast.Apple'". However, if I change the line to use the as operator, it compiles without error:

Apple apple = fruit as Apple;

有人可以解释为什么会出现这种情况吗?

Could someone please explain why this is the case?

推荐答案

我用这个问题作为 2015年10月的博客文章。非常感谢您提出的问题!

I used this question as the basis for a blog article in October 2015. Thanks for the great question!


有人可以解释为什么会出现这种情况吗?

Could someone please explain why this is the case?

为什么问题很难回答;答案是因为这是规范说,然后自然的问题是为什么规范说这样?

"Why" questions are hard to answer; the answer is "because that's what the spec says" and then the natural question is "why does the spec say that?"

所以让我让问题更清晰:

So let me make the question more crisp:


什么语言设计因素影响决定使给定投放操作符在约束类型参数上是非法的?

What language design factors influenced the decision to make the given cast operator illegal on constrained type parameters?

请考虑以下情况。你有一个基本类型水果,派生类型苹果和香蕉,现在是重要的一部分,从苹果到香蕉的用户定义的转换。

Consider the following scenario. You have a base type Fruit, derived types Apple and Banana, and, now comes the important part, a user-defined conversion from Apple to Banana.

当调用 M

void M<T>(T t) where T : Fruit
{
    Banana b = (Banana)t;
}

大多数阅读代码的人会说这应该调用用户定义的转换从苹果到香蕉。但是C#泛型不是C ++模板;该方法从头开始重新编译每个通用构造。而是,该方法被编译一次,并且在该编译期间,为每个可能的通用实例化确定每个运算符的含义,包括casts。

Most people reading the code would say that this should call the user-defined conversion from Apple to Banana. But C# generics are not C++ templates; the method is not recompiled from scratch for every generic construction. Rather, the method is compiled once, and during that compilation the meaning of every operator, including casts, is determined for every possible generic instantiation.

M< Apple> 的正文必须有用户定义的转换。 M< Banana> 的正文将进行身份转换。 M< Cherry> 将是一个错误。 通用方法中的运算符不能有三种不同的含义,因此运算符被拒绝。

The body of M<Apple> would have to have a user-defined conversion. The body of M<Banana> would have an identity conversion. M<Cherry> would be an error. We cannot have three different meanings of an operator in a generic method, so the operator is rejected.

而您需要做的是:

void M<T>(T t) where T : Fruit
{
    Banana b = (Banana)(object)t;
}

现在两个转换都已清除。对象的转换是隐式引用转换;转换到Banana是一个显式的引用转换。用户定义的转换从不被调用,如果这是用Cherry构造的,那么错误是在运行时,而不是编译时,因为它始终是从对象发起

Now both conversions are clear. The conversion to object is an implicit reference conversion; the conversion to Banana is an explicit reference conversion. The user-defined conversion is never called, and if this is constructed with Cherry then the error is at runtime, not compile time, as it always is when casting from object.

as 运算符不像cast运算符;它总是意味着相同的事情,无论给定什么类型,因为作为运算符从未调用用户定义的转换。因此,它可以在一个演员是非法的上下文中使用。

The as operator is not like the cast operator; it always means the same thing no matter what types it is given because the as operator does not ever invoke a user-defined conversion. Therefore it can be used in a context where a cast would be illegal.

这篇关于为什么直接铸造失败,但“as”运算符在测试受限泛型类型时是否成功?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆