2012-05-17 5 views
1

Мне было интересно узнать, насколько я могу разглядеть разницу в производительности от других, имеющих опыт отражения и объекты DTO внутри службы WCF. У меня есть код ниже, который я использовал для создания объекта DTO из объекта Entity с использованием Linq.Отражение для создания объектов DTO в WCF

using (dashEntities context = new dashEntities()) 
     { 
      result = context.GetAlerts().Select(m => new AlertItemDTO() 
      { 

      }).ToList(); 

Другой программист при создании своей службы WCF написал Generic метод с помощью отражения, чтобы сделать то же самое преобразование:

private object TransferEntityToDTO(object dto, object entity) 
    { 
     Type entityType = entity.GetType(); 

     // Use reflection to get all properties 
     foreach (PropertyInfo propertyInfo in entityType.GetProperties()) 
     { 

      if (propertyInfo.CanRead) 
      { 

       List<PropertyInfo> dtoProperties = dto.GetType().GetProperties().ToList(); 

       foreach (PropertyInfo dtoProperty in dtoProperties) 
       { 

        if (dtoProperty.Name == propertyInfo.Name) 
        { 

         object value = propertyInfo.GetValue(entity, null); 

         if (value != null && value.ToString() != "" && value.ToString() != "1/1/0001 12:00:00 AM") 
         { 
          // This section gets the type of of the property and casts 
          // to it during runtime then sets it to the corresponding 
          // dto value: 

          // Get current class type 
          Type currentClassType = this.GetType(); 

          //Get type of property in entity object 
          Type propertyType = Type.GetType(propertyInfo.PropertyType.FullName); 

          // Get the Cast<T> method and define the type 
          MethodInfo castMethod = currentClassType.GetMethod("Cast").MakeGenericMethod(propertyType); 

          // Invoke the method giving value its true type 
          object castedObject = castMethod.Invoke(null, new object[] { value }); 

          dtoProperty.SetValue(dto, value, null); 

         } 
         break; 
        } 

       } 

      } 

     } 

     return dto; 
    } 

    /// <summary> 
    /// Used in TransferEntityToDTO to dynamically cast objects to 
    /// their correct types. 
    /// </summary> 
    /// <typeparam name="T">Type to cast object to</typeparam> 
    /// <param name="o">Object to be casted</param> 
    /// <returns>Object casted to correct type</returns> 
    public static T Cast<T>(object o) 
    { 
     return (T)o; 
    } 

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

Мой вопрос заключается в возможности сделать его общим, перевешивая производительность при использовании отражения, а если нет, то почему? Я нашел много путаных статей и ответов на то, что делает размышление дорогостоящим. Я предполагаю, что часть его заключается в том, что она должна искать объект, который ему нужен, даже не зная, вроде как использовать Generic Exception для всего, когда вы знаете, какое исключение вы получите.

Может кто-то пролить свет на это для меня, пожалуйста. Спасибо

ответ

1

Основное отличие этих двух решений состоит в том, что первый использует проекцию, а второй отображает исходный объект. Для объектов, которые являются лишь небольшим поднабором исходного объекта (например, dtos для списков), всегда должно быть быстрее запрашивать только проецируемые свойства вместо полного объекта (возможно, с вложенными объектами и свойствами, которые вам не нужны ...) , который затем отображается на dto.

Чтобы объединить преимущества обоих решений (проекционных + общее решение) можно автоматически создавать проекционные выражения, кэшировать их и использовать их в Select (Expression < ...>) вызов, как в исходном растворе. Таким образом, все сопоставления создаются только один раз, вы получаете свои dtos напрямую и запрашиваете только необходимые столбцы. Посмотрите эту статью и комментарии: Stop using AutoMapper in your Data Access Code.

AutoMapper также может создавать выражения отображения, но он отображает только простые свойства (насколько я понял это из исходного кода). С настраиваемым решением и некоторой «выражением магией» можно также поддерживать сложные отображения, которые затем переведены в SQL с помощью структуры объекта:

ContactName = Contact.Name, 
AddressStreetAndNumber = (Address.Street + (" " + Address.Number)).Trim() 

Этого код here on github является хорошей отправной точкой.

3

Если вы посмотрите на некоторые из популярных библиотек сопоставления с открытым исходным кодом, таких как AutoMapper, EmitMapper или ValueInjecter, вы увидите, что они больше не используют метод отражения, вместо этого они используют такие вещи, как compiled expression trees and IL generation to speed things up.

Очевидно, что это делает их более сложными внутри (они все еще очень просты в использовании), чем основной рефлексионный калькулятор, но, как обычно, оптимизация скорости повышает сложность.

Мое мнение таково, что вы должны использовать одну из этих (отличных) библиотек с открытым исходным кодом, где авторы потратили много времени, рассматривая много вопросов так же, как и ваши.

+0

Благодарим вас за понимание, поскольку я не знал об этой библиотеке и других подобных, которые уже учитывали эти вещи. На данный момент, из-за нехватки времени, чтобы проверить его и других подобных, я хотел бы придерживаться этих двух сценариев, чтобы увидеть, что лучше использовать? По крайней мере, время от времени в течение следующих нескольких месяцев тестируйте и вводите эти новые библиотеки. – gcoleman0828

+0

@ gcoleman0828: Я предлагаю вам не сворачивать собственное решение и вместо этого использовать библиотеки. Они сложны только под капотом, но на самом деле очень просты в использовании. Они также хорошо протестированы и предлагают отличную производительность. –

0

Возможно, некоторые облегченные ОРМ будут полезны. Например, Dapper или Petapoco. Они могут связывать результат запроса SQL с динамическим или статическим объектом с помощью IL (Emit)

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