2013-07-21 3 views
6

Вместо того, чтобы перегружать функцию 100 раз или создавать 100 разных Comparers для разных типов, я решил проверить тип внутри одной функции.Что является самым быстрым способом проверки типа?

Например, я использую сопоставление по умолчанию для сравнения значений набора типов (примитивов и строк) в пределах 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 так же быстро, как это технически возможно, потому что он будет использоваться для больших коллекций данных.

Вопрос: Есть ли более быстрый способ проверить тип объекта (который не включает сравнение строк)? Каков самый быстрый способ?

+1

Вы ищете 'Comparer.Default'. – SLaks

+0

Или вызов ((IComparable) a) .CompareTo (b) – usr

+0

Нет. Я не ищу 'Comparer.Default'. Я редактировал свой пост, чтобы сделать его более понятным. Мой вопрос - это быстрый способ проверить тип. – brandon

ответ

6

У вас есть это в ваших руках. Использовать 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; 
     } 

это поддерживает все примитивы. для пользовательских объектов. Напишите else if утверждения внутри TypeCode.Object.

Надеюсь, это поможет.

+0

Да, тесты показывают, что ваш метод выполняется быстрее. Я не знал о перечислении 'TypeCode'. – brandon

+0

@brandon приветствует, теперь вы знаете об этом. –

+0

@brandon Я предлагаю вам применить соответствующий тип и сохранить его в локальной переменной, а затем сравнить для производительности вместо 'Unboxing' дважды –

3

Из комментариев это звучит так, как будто у вас есть куча структурированных данных, с подобъектами различного типа.

Если коллекции большие, самым быстрым способом будет динамический codegen (возможно, с деревьями выражений), чтобы создать единый метод, который вытягивает все поля/свойства, представляющие интерес, строго типизированным способом и выполняет строго типизированные сравнения.

В принципе, вы используете отражение, чтобы динамически получать типы полей/свойств из типа элемента коллекции. Затем вы создаете выражения MemberAccessExpression, передайте их Expression.Equal, а все результаты - Expression.AndAlso. Компиляция выражения дает вам делегат, который принимает два объекта определенного типа, содержащиеся в коллекции.

Время запуска будет на пару порядков медленнее, чем код, который вы указали в своем вопросе, но стоимость за объект будет намного ниже. Вам нужно будет проверить, где находится точка безубыточности, но, вероятно, на низких тысячах.

Смежные вопросы