C#generics和types检查

我有一个使用IList<T>作为参数的方法。 我需要检查T对象的types,并根据它做一些事情。 我试图使用T值,但编译器不允许它。 我的解决scheme如下:

 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的types,然后使用switch语句?

你可以使用重载:

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

或者你可以检查generics参数的types:

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

你可以使用typeof(T)

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

默认情况下知道没有一个好方法。 有一段时间,我对此感到沮丧,并写了一个小实用程序类,帮助了一下,使语法更清洁。 本质上,它将代码转换成

 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 

完整的博客文章和实施细节可在这里find

操作符的types…

 typeof(T) 

…不会与c#switch语句一起工作。 但是这个怎么样? 以下post包含一个静态类…

有没有比这更好的替代“打开types”?

…这将让你写这样的代码:

 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")); 

你的build筑完全失败了一个通用方法的目的。 这是丑陋的目的,因为必须有一个更好的方式来实现你想要完成的,虽然你没有给我们足够的信息来弄清楚是什么。

对于每个人来说,检查types和根据types做一些事情对于我所认同的generics来说并不是一个好主意,但我认为在某些情况下这是完全合理的。

例如,如果你有一个类实现了这样的类(注意:我没有显示这个代码为了简单而做的所有事情,并且只是简单地剪切并粘贴到这里,所以它可能不像整个代码那样构build或工作,它得到了重点。此外,单位是一个枚举):

 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(); } 

所以总的来说,我认为有一些合理的理由可以检查通用types是什么types,以便做一些特殊的事情。

没有办法使用switch语句来执行你想要的操作。 switch语句必须提供整型,不包括诸如“Type”对象之类的复杂types或任何其他对象types。

你可以做typeOf(T) ,但我会仔细检查你的方法,并确保你没有违反单一的责任在这里。 这将是一个代码味道,这并不是说不应该做,但你应该谨慎。

generics的要点是能够构buildtypes不可知的algorthims,只要它符合一定的标准,你不关心types是什么types。 你的实现不是非常通用的。

这个怎么样 :

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