C# 泛型和类型检查
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/982952/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# Generics and Type Checking
提问by Jon
I have a method that uses an IList<T>
as a parameter. I need to check what the type of that T
object is and do something based on it. I was trying to use the T
value, but the compiler does not not allow it. My solution is the following:
我有一个使用 anIList<T>
作为参数的方法。我需要检查该T
对象的类型并根据它做一些事情。我试图使用该T
值,但编译器不允许。我的解决方案如下:
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");
}
}
}
There has to be a better way to do this. Is there some way I can check the type of T
that is passed in and then use a switch
statement?
必须有更好的方法来做到这一点。有什么方法可以检查T
传入的类型然后使用switch
语句吗?
采纳答案by jonnii
You could use overloads:
您可以使用重载:
public static string BuildClause(List<string> l){...}
public static string BuildClause(List<int> l){...}
public static string BuildClause<T>(List<T> l){...}
Or you could inspect the type of the generic parameter:
或者您可以检查泛型参数的类型:
Type listType = typeof(T);
if(listType == typeof(int)){...}
回答by Robert Harvey
The typeof operator...
运算符的类型...
typeof(T)
... won't work with the c# switch statement. But how about this? The following post contains a static class...
... 不适用于 c# switch 语句。但这又如何呢?以下帖子包含一个静态类...
Is there a better alternative than this to 'switch on type'?
...that will let you write code like this:
...这会让你编写这样的代码:
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"));
回答by bdowden
You can use typeof(T)
.
您可以使用typeof(T)
.
private static string BuildClause<T>(IList<T> clause)
{
Type itemType = typeof(T);
if(itemType == typeof(int) || itemType == typeof(decimal))
...
}
回答by JoshBerke
You can do typeOf(T)
, but I would double check your method and make sure your not violating single responsability here. This would be a code smell, and that's not to say it shouldn't be done but that you should be cautious.
你可以这样做typeOf(T)
,但我会仔细检查你的方法,并确保你没有在这里违反单一责任。这将是一种代码异味,并不是说不应该这样做,而是说您应该谨慎。
The point of generics is being able to build type-agnostic algorthims were you don't care what the type is or as long as it fits within a certain set of criteria. Your implementation isn't very generic.
泛型的要点是能够构建与类型无关的算法,只要您不关心类型是什么,或者只要它符合特定的一组标准。您的实现不是很通用。
回答by womp
There is no way to use the switch statement for what you want it to do. The switch statement must be supplied with integral types, which does not include complex types such as a "Type" object, or any other object type for that matter.
没有办法使用 switch 语句来完成你想要它做的事情。switch 语句必须提供整数类型,不包括复杂类型,例如“类型”对象,或任何其他与此相关的对象类型。
回答by mqp
Your construction completely defeats the purpose of a generic method. It's ugly on purpose because there must be a better way to achieve what you're trying to accomplish, although you haven't given us quite enough information to figure out what that is.
您的构造完全违背了泛型方法的目的。这是故意的丑陋,因为必须有更好的方法来实现你想要完成的目标,尽管你没有给我们足够的信息来弄清楚那是什么。
回答by JaredPar
By default know there is not a great way. Awhile back I got frustrated with this and wrote a little utility class that helped out a bit and made the syntax a bit cleaner. Essentially it turns the code into
默认情况下知道没有什么好方法。不久前,我对此感到沮丧,并编写了一个小实用程序类,它有所帮助并使语法更简洁。本质上它把代码变成
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
Full blog post and details on the implementation are available here
完整的博客文章和有关实施的详细信息可在此处获得
回答by John
For everyone that says checking types and doing something based on the type is not a great idea for generics I sort of agree but I think there could be some circumstances where this perfectly makes sense.
对于那些说检查类型并根据类型做一些事情对于泛型来说不是一个好主意的人,我有点同意,但我认为可能在某些情况下这完全有意义。
For example if you have a class that say is implemented like so (Note: I am not showing everything that this code does for simplicity and have simply cut and pasted into here so it may not build or work as intended like the entire code does but it gets the point across. Also, Unit is an enum):
例如,如果你有一个这样实现的类(注意:为了简单起见,我没有展示这段代码所做的一切,只是简单地剪切并粘贴到这里,所以它可能不会像整个代码那样构建或工作,但是它得到了重点。另外,Unit是一个枚举):
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();
}
So in summary, I think there are valid reasons why you might want to check to see what type the generic is, in order to do something special.
总而言之,我认为您可能想要检查泛型是什么类型,以便做一些特殊的事情,这是有正当理由的。
回答by Bert
How about this :
这个怎么样 :
// Checks to see if the value passed is valid.
if (!TypeDescriptor.GetConverter(typeof(T)).IsValid(value))
{
throw new ArgumentException();
}
回答by Jaider
I hope you find this helpful:
我希望你觉得这有用:
typeof(IList<T>).IsGenericType == true
typeof(IList<T>).GetGenericTypeDefinition() == typeof(IList<>)
typeof(IList<int>).GetGenericArguments()[0] == typeof(int)
typeof(IList<T>).IsGenericType == true
typeof(IList<T>).GetGenericTypeDefinition() == typeof(IList<>)
typeof(IList<int>).GetGenericArguments()[0] == typeof(int)