2009-06-11 97 views
43

我有一個使用IList<T>作爲參數的方法。我需要檢查那個對象的類型是什麼,並根據它做些事情。我試圖使用T的值,但編譯器不允許。我的解決方案如下:C#泛型和類型檢查

private static string BuildClause<T>(IList<T> clause) 
{ 
    if (clause.Count > 0) 
    { 
     if (clause[0] is int || clause[0] is decimal) 
     { 
      //do something 
     } 
     else if (clause[0] is String) 
     { 
      //do something else 
     } 
     else if (...) //etc for all the types 
     else 
     { 
      throw new ApplicationException("Invalid type"); 
     } 
    } 
} 

必須有更好的方法來做到這一點。有什麼方法可以檢查傳入的T的類型,然後使用switch聲明?

+1

我個人想知道你在每個數據類型做什麼特別的。如果您對每種數據類型進行大致相同的轉換,將不同類型映射到通用接口並在該接口上操作可能會更容易。 – Juliet 2009-06-11 19:18:25

回答

68

你可以使用重載:

public static string BuildClause(List<string> l){...} 

public static string BuildClause(List<int> l){...} 

public static string BuildClause<T>(List<T> l){...} 

或者你可以檢查泛型參數的類型:

Type listType = typeof(T); 
if(listType == typeof(int)){...} 
+14

+1:在設計和長期可維護性方面,過載絕對是最好的解決方案。一個通用參數的運行時類型檢查似乎太過諷刺,以致於無法直接編碼。 – Juliet 2009-06-11 19:14:17

4

typeof運算符...

typeof(T) 

...不會與C#switch語句工作。但是這個怎麼樣?下面的帖子包含一個靜態類...

Is there a better alternative than this to 'switch on type'?

...這將讓你寫這樣的代碼:

TypeSwitch.Do(
    sender, 
    TypeSwitch.Case<Button>(() => textBox1.Text = "Hit a Button"), 
    TypeSwitch.Case<CheckBox>(x => textBox1.Text = "Checkbox is " + x.Checked), 
    TypeSwitch.Default(() => textBox1.Text = "Not sure what is hovered over")); 
+0

另請參閱JaredPar的答案。 – 2009-06-11 19:11:59

11

您可以使用typeof(T)

private static string BuildClause<T>(IList<T> clause) 
{ 
    Type itemType = typeof(T); 
    if(itemType == typeof(int) || itemType == typeof(decimal)) 
    ... 
} 
1

你可以做typeOf(T),但我會仔細檢查你的方法,並確保你不在這裏違反單一責任。這將是一種代碼味道,這並不是說它不應該做,而是應該謹慎。

仿製藥的點能夠建立類型無關algorthims是你不在乎什麼類型是或,只要它一組特定的標準範圍內配合。你的實現不是非常通用的。

1

沒有辦法使用switch語句你想要它做的事情。 switch語句必須以整型提供,它不包含複雜類型,例如「類型」對象或任何其他對象類型。

2

你的建築完全失敗了通用方法的目的。這是醜陋的目的,因爲必須有更好的方式來實現你想要完成的事情,儘管你沒有給我們足夠的信息來弄清楚它是什麼。

6

默認情況下知道沒有一個好方法。一段時間後,我對此感到沮喪,並寫了一個小實用程序類,幫助了一下,並使語法更清晰。本質上,它變成代碼爲

TypeSwitcher.Do(clause[0], 
    TypeSwitch.Case<int>(x => ...), // x is an int 
    TypeSwitch.Case<decimal>(d => ...), // d is a decimal 
    TypeSwitch.Case<string>(s => ...)); // s is a string 

完整的博客文章和細節上的執行都可以在這裏

2

對於逢人就說檢查類型和基於該類型做什麼對於我所同意的仿製藥並不是一個好主意,但我認爲在某些情況下這是完全合理的。例如,如果你有一個類說是像這樣實現的(注意:我沒有顯示這個代碼爲了簡單而做的所有事情,並且只是簡單地剪切並粘貼到這裏,所以它可能無法像預期那樣構建或工作,整個代碼做,但它跨越得到一點此外,單位是一個枚舉):

public class FoodCount<TValue> : BaseFoodCount 
{ 
    public TValue Value { get; set; } 

    public override string ToString() 
    { 
     if (Value is decimal) 
     { 
      // Code not cleaned up yet 
      // Some code and values defined in base class 

      mstrValue = Value.ToString(); 
      decimal mdecValue; 
      decimal.TryParse(mstrValue, out mdecValue); 

      mstrValue = decimal.Round(mdecValue).ToString(); 

      mstrValue = mstrValue + mstrUnitOfMeasurement; 
      return mstrValue; 
     } 
     else 
     { 
      // Simply return a string 
      string str = Value.ToString() + mstrUnitOfMeasurement; 
      return str; 
     } 
    } 
} 

...

public class SaturatedFat : FoodCountWithDailyValue<decimal> 
{ 
    public SaturatedFat() 
    { 
     mUnit = Unit.g; 
    } 

} 

public class Fiber : FoodCount<int> 
{ 
    public Fiber() 
    { 
     mUnit = Unit.g; 
    } 
} 

public void DoSomething() 
{ 
     nutritionFields.SaturatedFat oSatFat = new nutritionFields.SaturatedFat(); 

     string mstrValueToDisplayPreFormatted= oSatFat.ToString(); 
} 

因此,在總結,我認爲有正當的理由,爲什麼你可能要檢查通用類型是什麼類型,以便做一些特殊的事情。

0

如何:

  // Checks to see if the value passed is valid. 
      if (!TypeDescriptor.GetConverter(typeof(T)).IsValid(value)) 
      { 
       throw new ArgumentException(); 
      }