代码之家  ›  专栏  ›  技术社区  ›  Jon

C泛型和类型检查

  •  56
  • Jon  · 技术社区  · 16 年前

    我有一个方法使用 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 回复  |  直到 16 年前
        1
  •  86
  •   jonnii    16 年前

    可以使用重载:

    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)){...}
    
        2
  •  16
  •   J0e3gan    10 年前

    你可以使用 typeof(T) .

    private static string BuildClause<T>(IList<T> clause)
    {
         Type itemType = typeof(T);
         if(itemType == typeof(int) || itemType == typeof(decimal))
        ...
    }
    
        3
  •  6
  •   JaredPar    16 年前

    默认情况下,知道没有什么好方法。不久前,我对这个感到很沮丧,写了一个实用程序类,帮助了一点,使语法更加清晰。从本质上讲,它将代码转换为

    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
    

    这里提供完整的博客文章和有关实现的详细信息

        4
  •  4
  •   Community CDub    8 年前

    操作员类型…

    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"));
    
        5
  •  2
  •   mqp    16 年前

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

        6
  •  2
  •   Dio F    12 年前

    对于每个说检查类型并基于类型做一些事情的人来说,对于泛型来说不是一个好主意,我有点同意,但我认为在某些情况下,这完全有意义。

    例如,如果您有一个类说它是这样实现的(注意:我并不是为了简单而展示这段代码所做的一切,而是简单地剪切和粘贴到这里,这样它可能不会像整个代码那样构建或工作,但它会得到重点。此外,单位是枚举):

    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
  •   womp    16 年前

    无法将switch语句用于您希望它执行的操作。switch语句必须与整型一起提供,整型不包括“type”对象等复杂类型,也不包括与此相关的任何其他对象类型。

        8
  •  1
  •   J0e3gan    10 年前

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

    泛型的要点是能够构建类型不可知的Algorthims,如果您不关心类型是什么,或者只要它符合某一组标准。您的实现不是非常通用的。

        9
  •  0
  •   Bert    10 年前

    这个怎么样:

                // Checks to see if the value passed is valid. 
                if (!TypeDescriptor.GetConverter(typeof(T)).IsValid(value))
                {
                    throw new ArgumentException();
                }
    
        10
  •  0
  •   Jaider    6 年前

    我希望你觉得这有帮助:

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

    https://dotnetfiddle.net/5qUZnt

        11
  •  0
  •   Kit    6 年前

    而且,因为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");
            }
        }
    }