C#泛型和类型检查

时间:2009-06-11 18:56:27

标签: c# generics types

我有一个使用IList<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");
        }
    } 
}

必须有更好的方法来做到这一点。有什么方法可以检查传入的T类型然后使用switch语句吗?

11 个答案:

答案 0 :(得分:88)

您可以使用重载:

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)){...}

答案 1 :(得分:16)

您可以使用typeof(T)

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

答案 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

完整的博客文章和有关实施的详细信息可在此处获取

答案 3 :(得分:4)

运营商类型......

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

答案 4 :(得分:2)

无法将switch语句用于您想要的操作。必须为switch语句提供整数类型,这些类型不包括复杂类型,例如“类型”对象或任何其他对象类型。

答案 5 :(得分:2)

您的构造完全违背了通用方法的目的。它的目的很丑陋,因为必须有更好的方法来实现你想要完成的目标,尽管你还没有给我们足够的信息来弄清楚它是什么。

答案 6 :(得分:2)

对于每个人都说根据类型检查类型和做某事对于泛型不是一个好主意我有点同意,但我认为在某些情况下这可能是完全有道理的。

例如,如果你有一个类是这样实现的(注意:我没有显示这段代码为简单而做的所有事情,只是剪切并粘贴到这里,所以它可能无法构建或按预期工作,就像整个代码确实如此,但它得到了重点。另外,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();
}

总而言之,我认为为了做一些特别的事情,你可能想检查一下通用的类型是有正当理由的。

答案 7 :(得分:1)

您可以执行typeOf(T),但我会仔细检查您的方法,并确保您不违反单一责任。这将是一种代码味道,并不是说不应该这样做,而是你应该谨慎。

泛型的观点是能够构建与类型无关的算法,如果您不关心类型是什么,或者只要它符合某组标准。你的实现不是很通用。

答案 8 :(得分:0)

这个怎么样:

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

答案 9 :(得分:0)

希望您对此有帮助:

  • typeof(IList<T>).IsGenericType == true
  • typeof(IList<T>).GetGenericTypeDefinition() == typeof(IList<>)
  • typeof(IList<int>).GetGenericArguments()[0] == typeof(int)

https://dotnetfiddle.net/5qUZnt

答案 10 :(得分:0)

而且,由于C#不断发展,您可以(现在)使用pattern matching

private static string BuildClause<T>(IList<T> clause)
{
    if (clause.Count > 0)
    {
        switch (clause[0])
        {
            case int x: // do something with x, which is an int here...
            case decimal x: // do something with x, which is a decimal here...
            case string x: // do something with x, which is a string here...
            ...
            default: throw new ApplicationException("Invalid type");
        }
    }
}