簡體   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