[英]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.