15

在最近重构了一些代码之后,其中涉及一些类重命名,我的一些代码以一种令人惊讶的方式破坏了。原因是失败的“is”运算符测试,我很惊讶不是编译器错误或警告。

这个完整的程序显示了这种情况:

static class ExtensionMethods {}

class Program {

    static void Main() {
        Test("Test");
    }

    public static bool Test(object obj)
    {
        return obj is ExtensionMethods;
    }
}

鉴于 ExtensionMethods 是一个静态类,我本来希望“obj is ExtensionMethods”会发出某种警告。

例如,当被测对象永远不能是提供的类型时,编译器将为“is”运算符发出警告((string)obj) is System.Uri

我是否忘记了这实际上是一个有意义的测试的场景?

4

5 回答 5

11

我很惊讶不是编译器错误或警告。

应该是的。这是一个疏忽。

有许多类似涉及静态类的错误。如果我没记错的话,Vladimir Reshetnikov 甚至发现了一些奇怪的场景,可以在其中进行类型推断,将静态类型推断为类型参数的绑定。

显然,我以前见过的这个,从来没有得到修复。为疏忽道歉。

我是否忘记了这实际上是一个有意义的测试的场景?

不。

于 2013-02-15T01:58:19.587 回答
4

从 C# 3.0 规范,第 10.1.1.3 节:

静态类可能不包括基于类的规范(第 10.1.4 节),并且不能显式指定基类或已实现接口的列表。静态类隐式继承自类型对象。

因此,编译器显然不会发出警告,因为它不知道is将始终返回 false。(静态类“是” an object,因此编译器在编译时不知道object“is”或“is”不是静态类。)实际上它可能确实知道,或者至少可以找出,但显然它不专门研究这种情况并检查。

于 2013-02-15T00:19:52.600 回答
1

我对此进行了破解,虽然我在 MSDN 参考中找不到它,但似乎 is 操作符依赖于实例化一个能够检查的类型。由于静态类不能被实例化(因为静态类是在编译时在程序堆栈上创建的对象)......

例如,如果您执行以下操作,则会收到以下错误:“无法声明静态类型的变量”

ExtensionMethods ex;

如果您执行以下操作,您也不会收到以下错误:“无法创建静态类的实例”

ExtensionMethods ex2 = new ExtensionMethods();

为了演示这个问题,这里有一个完整的程序,显示了 is 运算符。

static class ExtensionMethods { }

// notice non-static
class AnotherNonStaticExtensionMethod { }

class Program
{
    static void Main(string[] args)
    {
        Debug.WriteLine(Test(new AnotherNonStaticExtensionMethod()).ToString());
        Debug.WriteLine(Test("Test").ToString());
        Debug.WriteLine(Test(4).ToString());
    }

    public static bool Test(object obj)
    {
        if (obj is ExtensionMethods)
        {
            return true;
        }
        else if (obj is AnotherNonStaticExtensionMethod)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

这是以下输出:

True
False
False

is 对象能够使用第一条语句检查可实例化的类——因此让我相信 is 运算符依赖于它。我希望有人可以证实这一点?

由 NominSim 提供::

从 C# 3.0 规范,第 10.1.1.3 节:

静态类可能不包括基于类的规范(第 10.1.4 节),并且不能显式指定基类或已实现接口的列表。静态类隐式继承自类型对象。

于 2013-02-15T00:19:43.783 回答
1

Eric Lippert 2013 年的回答解释说这是 Visual C# 5.0 编译器(以及一些早期版本)中的一个错误。as例如,操作员也存在问题object bad = obj as ExtensionMethods;

在 C# 6.0(从 2015 年开始)及更高版本中,您确实会收到编译时错误(不仅仅是警告):

错误 CS7023:“is”或“as”运算符的第二个操作数可能不是静态类型“Xxxx”

但是,仅当您指定功能 Strict 时才适用,有关如何执行此操作的详细信息,请参阅另一个线程

于 2017-05-04T14:18:39.520 回答
0

根据 C# 语言规范:

is 运算符用于动态检查对象的运行时类型是否与给定类型兼容。操作 E 的结果是 T,其中 E 是表达式,T 是类型,是一个布尔值,指示 E 是否可以通过引用转换、装箱转换或拆箱转换成功地转换为 T 类型。

静态类可能不包括基于类的规范(第 10.1.4 节),并且不能显式指定基类或已实现接口的列表。静态类隐式继承自类型对象。

由于它隐式继承自System.Object,因此编译器没有发出警告是有道理的。

确认:

var staticBaseType = typeof(B).BaseType;

您将获得 aSystem.Object作为基本类型。

于 2013-02-15T00:46:44.917 回答