繁体   English   中英

C#静态类和is运算符

[英]C# static classes and the is operator

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

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

static class ExtensionMethods {}

class Program {

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

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

鉴于ExtensionMethods是一个静态类,我本来期望“obj是ExtensionMethods”来引发某种警告。

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

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

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

它应该是。 这是一种疏忽。

有许多错误,比如涉及静态类。 如果我没记错的话,甚至有一些奇怪的情况,Vladimir Reshetnikov发现可以进行类型推断的地方推断静态类型作为类型参数的约束。

显然,我之前见过的这个,从未得到修复。 为疏忽道歉。

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

没有。

从C#3.0规范,第10.1.1.3节:

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

因此编译器显然不会引发警告,因为它不知道is总是返回false。 (静态类“是”的object ,因此,编译器不知道的object “是”或“是”不是在编译时静态类)。现实情况可能知道,或者至少能找到 ,但显然它没有专门的情况和检查。

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

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

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节),并且不能显式指定基类或已实现接口的列表。 静态类隐式继承自类型对象。

Eric Lippert从2013年开始的回答解释说这是Visual C#5.0编译器(以及一些早期版本)中的一个错误。 问题在于as运算符,例如object bad = obj as ExtensionMethods;

在C#6.0(从2015年开始)以及之后,您会收到编译时错误(而不仅仅是警告):

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

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

根据C#语言规范:

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

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

由于它隐式地从System.Object继承,因此编译器不发出警告是有意义的。

验证:

var staticBaseType = typeof(B).BaseType;

您将获得一个System.Object作为基本类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM