【问题标题】:What is the fastest way to check a type?检查类型的最快方法是什么?
【发布时间】:2013-07-22 00:32:47
【问题描述】:

我决定检查一个函数中的类型,而不是重载一个函数 100 次或为不同类型创建 100 个不同的比较器。

例如,我使用默认比较器来比较 2 个对象内的一组类型(基元和字符串)的值。它包含以下代码:

public class DefComparer : IComparer<object> {
    public int Compare(object a, object b) {
        .... // a = a.GetType().GetField(field).GetValue(a); - not important for the question but I'm just showing that a&b below are different references
        switch (a.GetType().Name) {
            case "Byte":
                if ((byte)a == (byte)b) return 0;
                else if ((byte)a > (byte)b) return 1;
                else return -1;
            case "UInt16":
                if ((ushort)a == (ushort)b) return 0;
                else if ((ushort)a > (ushort)b) return 1;
                else return -1;
            case "SByte":
                if ((sbyte)a == (sbyte)b) return 0;
                else if ((sbyte)a > (sbyte)b) return 1;
                else return -1;
            case "Int16":
                ...

这里我使用了switch 语句,据说它比if/else 语句链更快。但是a.GetType().Name返回的是一个动态获取的字符串,这个方法涉及到字符串比较。这对我来说听起来不是特别快。我需要比较器在技术上尽可能快,因为它将用于大量数据集合。

问:有没有更快的方法来检查对象的类型(不涉及字符串比较)?最快的方法是什么?

【问题讨论】:

  • 您正在寻找Comparer.Default
  • 或者调用 ((IComparable)a).CompareTo(b)
  • 不,我不是在寻找Comparer.Default。我已经编辑了我的帖子以使其更加清晰。我的问题是关于检查类型的快速方法。
  • 这些是混合类型的大型集合,还是单一类型但类型未知的大型组?
  • @usr 不确定这是否更快,但我会检查一下。

标签: c# performance reflection types


【解决方案1】:

好吧,你已经掌握了它。使用TypeCode

        int a = 10;
        Type t = a.GetType();

        switch (Type.GetTypeCode(t))
        {
            case TypeCode.Boolean:
                break;
            case TypeCode.Byte:
                break;
            case TypeCode.Char:
                break;
            case TypeCode.DBNull:
                break;
            case TypeCode.DateTime:
                break;
            case TypeCode.Decimal:
                break;
            case TypeCode.Double:
                break;
            case TypeCode.Empty:
                break;
            case TypeCode.Int16:
                break;
            case TypeCode.Int32:
                break;
            case TypeCode.Int64:
                break;
            case TypeCode.Object:
                break;
            case TypeCode.SByte:
                break;
            case TypeCode.Single:
                break;
            case TypeCode.String:
                break;
            case TypeCode.UInt16:
                break;
            case TypeCode.UInt32:
                break;
            case TypeCode.UInt64:
                break;
            default:
                break;
        }

这支持所有原语。对于自定义对象,在 TypeCode.Object 中写入 else if 语句。

我希望这会有所帮助。

【讨论】:

  • 是的,测试表明您的方法更快。我不知道TypeCode 枚举。
  • @brandon 我建议您转换为适当的类型并将其存储在局部变量中,然后比较性能而不是 Unboxing 两次
  • 你是对的。来自 msdn:相对于简单的分配,装箱和拆箱是计算成本很高的过程。当一个值类型被装箱时,必须分配和构造一个新对象。在较小程度上,拆箱所需的演员表在计算上也很昂贵。感谢您提供的信息
  • 如何将它与int?等可空类型一起使用?
  • @jocull 使用Nullable.GetUnderlyingType 方法
【解决方案2】:

从 cmets 看来,您好像有一堆结构化数据,带有不同类型的子对象。

如果集合很大,最快的方法是动态代码生成(可能使用表达式树)来创建一个方法,以强类型的方式提取所有感兴趣的字段/属性,并执行强类型比较。

基本上,您使用反射从集合成员类型中动态获取字段/属性类型。然后构建MemberAccessExpression 表达式,将它们传递给Expression.Equal,并将所有结果传递给Expression.AndAlso。编译表达式会为您提供一个委托,该委托接受集合中包含的特定类型的两个对象。

启动时间将比您在问题中显示的代码慢几个数量级,但每个对象的成本会低很多。您必须进行测试才能看到盈亏平衡点在哪里——但可能在几千以下。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 2011-07-13
    • 2014-01-28
    • 2019-08-20
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多