What is the fastest way to check a type?

2019-04-28 02:57发布

Instead of overloading a function 100 times or creating 100 different Comparers for different types I've decided to check the type within one function.

For example I'm using a default comparer to compare values of a set of types (primitives and strings) within 2 objects. It contains the following code:

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":
                ...

Here I'm using a switch statement that is said to be faster than a chain of if/else statements. But a.GetType().Name returns a string that is dynamically obtained and this method involves string comparisons. That doesn't sound particularly fast to me. I need the Comparer to be as fast as technically possible because It's going to be used on large collections of data.

Q: Is there a faster way to check the type of an object (that does not involve string comparisons)? What is the fastest possible way?

2条回答
闹够了就滚
2楼-- · 2019-04-28 03:36

Well you have it in your hand. Use 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;
        }

this supports all primitives. for Custom objects Write else if statements inside TypeCode.Object.

I hope this helps.

查看更多
Animai°情兽
3楼-- · 2019-04-28 03:38

From the comments, it sounds as if you have a bunch of structured data, with subobjects of varying type.

If the collections are large, the fastest way will be dynamic codegen (with expression trees perhaps) to create a single method that pulls all the fields/properties of interest out in a strongly typed way, and performs strongly typed comparisons.

Basically, you use reflection to get the field/property types dynamically from the collection member type. Then you build MemberAccessExpression expressions, pass those to Expression.Equal, and all the results to Expression.AndAlso. Compiling the expression gives you a delegate that takes two objects of the particular type contained in the collection.

Startup time will be a couple orders of magnitude slower than the code you showed in your question, but the cost per-object will be a whole lot lower. You'll have to test to see where the breakeven point is -- but probably in the low thousands.

查看更多
登录 后发表回答