C#静态类和is运算符

时间:2013-02-14 23:55:32

标签: c#

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

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

static class ExtensionMethods {}

class Program {

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

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

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

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

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

5 个答案:

答案 0 :(得分:11)

  

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

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

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

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

  

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

没有

答案 1 :(得分:4)

从C#3.0规范,第10.1.1.3节:

  

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

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

答案 2 :(得分:1)

我对此采取了一个破解,虽然我在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节)   并且无法显式指定基类或已实现的列表   接口。静态类隐式继承自类型对象。

答案 3 :(得分:1)

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

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

  

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

但是,只有在指定功能Strict时才会出现这种情况,请参阅another thread for details on how to do that

答案 4 :(得分:0)

根据C#语言规范:

  

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

  

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

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

验证

var staticBaseType = typeof(B).BaseType;

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