簡體   English   中英

為什么C#switch語句不允許使用typeof / GetType()?

[英]Why doesn't C# switch statement allow using typeof/GetType()?

如本例所示:

switch ( myObj.GetType ( ) )
{
    case typeof(MyObject):
        Console.WriteLine ( "MyObject is here" );
        break;
}

在Peter Hallam的職位上排名第二; 這是一個很好的解釋。

不過,您可以使用TypeCode處理簡單類型。

switch (Type.GetTypeCode(myObj.GetType())) {
    case TypeCode.Boolean: ...
    case TypeCode.Char: ...
    case TypeCode.String: ...
    case TypeCode.Object: ...
    default: ...
} 

我將在彼得的出色分析中加入以下思想:

剛出生時,“轉換”的目的是從一些不同的可能性中選擇一種 枚舉,整數,布爾值或字符串類型的給定值只能是一個值,因此“切換”該值是有意義的。 但是類型根本不同。 給定值通常具有許多類型。 類型經常重疊 提出的“類型開關”與開關構造的既定目的不匹配。

問題是(根據規范) switch (僅適用於原語(int等)和字符串)。 但是,是的, 具有F#樣式匹配會很好。

從§8.7.2開始:

 switch-label: case constant-expression : default : 

... switch語句的控制類型由switch表達式建立。 如果switch表達式的類型是sbyte,byte,short,ushort,int,uint,long,ulong,char,string或enum-type,則這就是switch語句的控制類型。 否則,從switch表達式的類型到以下可能的控制類型之一,必須存在一個用戶定義的隱式轉換(第6.4節):sbyte,byte,short,ushort,int,uint,long,ulong,char,string 。 如果不存在這樣的隱式轉換,或者存在多個這樣的隱式轉換,則會發生編譯時錯誤。

但是很明顯,使用這樣的受限集可以實現簡單(有效)的IL。 請注意, string是通過字典映射處理為整數的。

Peter Hallam在MSDN上有一篇不錯的博客文章,其中解釋了啟用非恆定值的問題。

“案例標簽的順序對於確定執行哪個代碼塊非常重要。由於案例標簽的表達式不是恆定的,因此編譯器無法驗證案例標簽的值是不同的,因此這是必須解決的可能性這與大多數程序員通過幾種方式對switch語句的直覺背道而馳,大多數程序員會驚訝地發現,改變其case塊的順序會改變其程序的含義。如果打開的表達式等於case標簽中的表達式,但控件沒有轉到該標簽。”

你可以做

switch ( myObj.GetType().Name )
{
    case "MyObject":
        Console.WriteLine ( "MyObject is here" );
        break;
}

之所以可行,是因為切換僅適用於原始類型(如其他人所述)。

就是typeof不是常數,而且情況必須是常數。

C#中的開關僅適用於整數或字符串。 myObj.GetType()返回一個Type,它既不是整數也不是字符串。

你為什么不只是tostring()呢?

在C#7.0中,您可以執行此操作。 請參見C#7.0案例塊中的模式匹配

// ----- Assume that spaceItem is of type SpaceType,
//       and that Planet and Star derive from SpaceType.
switch (spaceItem)
{
  case Planet p:
    if (p.Type != PlanetType.GasGiant)
      LandSpacecraft(p);
    break;
  case Star s:
    AvoidHeatSource(s);
    break;
  case null:
    // ----- If spaceItem is null, processing falls here,
    //       even if it is a Planet or Star null instance.
    break;
  default:
    // ----- Anything else that is not Planet, Star, or null.
    break;
}

除了懶惰之外,沒有充分的理由讓MS不執行類型切換。

字符串切換是通過使用“ if(.. Equals(..))”(少用)和Dictionary(多用)來完成的。 這兩種方法都是為所有.NET類型定義的,因為System.Object具有虛擬的Equals和GetHashCode。

有人會說,“ switch可以使用覆蓋Equals和GetHashCode的任何類型的表達式”,它會自動限定字符串,Type等。是的,糟糕的Equals / GetHashCode實現會破壞switch語句,但是,您也可以破壞“ ==”運算符,“ foreach”循環以及許多其他內容,所以我真的看不到“大問題”,因為程序員的錯誤破壞了開關。 但是,即使出於某種原因,即使他們不想允許所有類型都使用它,也可以肯定Type是安全的,因為Type.Equals()是定義明確的,並且還實現了GetHashCode。

另外,我不贊成您考慮繼承的說法。 切換到常量(並且type(int)是一個常量,請不要誤解)等於表達式的情況-繼承是Type類型的另一個“行為”。 一個人甚至不需要考慮繼承,我的意思是,我們是否僅因為兩個對象具有其他特性而拒絕比較它們? 不,我們不這樣做,因為總是定義平等。 基本上,重點是,不同類型之間沒有重疊。

因此,正如我所說,只有一個原因和一個原因:懶惰。 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM