【问题标题】:Reflection to make DTO objects in WCF在 WCF 中创建 DTO 对象的反射
【发布时间】:2012-05-17 12:44:47
【问题描述】:

我想知道是否可以从 WCF 服务中的反射和 DTO 对象的其他体验中找出性能差异。我有下面的代码,用于使用 Linq 从 Entity 对象创建 DTO 对象。

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

            }).ToList();

另一位程序员在构建他们的 WCF 服务时编写了一个通用方法,使用反射进行相同的转换:

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;
    }

显然,第二种技术更难阅读,也更冗长,但它更通用,可用于多种服务。

我的问题是,使其通用化的能力是否超过了使用反射对性能的影响?如果不是,为什么?我发现了很多令人困惑的文章和答案,说明什么使反射变得昂贵。我假设部分原因是因为它需要在不知道的情况下寻找它需要的对象,有点像当你知道你会得到的异常时使用通用异常。

请有人帮我解释一下。谢谢

【问题讨论】:

    标签: .net performance entity-framework reflection dto


    【解决方案1】:

    如果您查看一些流行的开源映射库,例如 AutoMapper、EmitMapper 或 ValueInjecter,您会发现它们不再使用反射方法,而是使用 compiled expression trees and IL generation to speed things up 之类的东西。

    显然,这使得它们在内部比基于反射的基本映射器更复杂(它们仍然非常易于使用),但像往常一样,优化速度会增加复杂性。

    我的意见是,您应该使用这些(优秀的)开源库中的一个,其中作者已经花费大量时间考虑许多问题,就像您的问题一样。

    【讨论】:

    • 感谢您的洞察力,因为我不知道这个图书馆和其他类似的图书馆已经考虑了这些事情。目前,由于没有时间测试它并且其他人喜欢它,我想坚持这两个场景,看看哪个更好用?至少在接下来的几个月里,测试并引入这些新库
    • @gcoleman0828:我建议您不要推出自己的解决方案,而是使用库。它们仅在引擎盖下很复杂,但实际上非常易于使用。它们也经过了良好的测试并提供了出色的性能。
    【解决方案2】:

    这两种解决方案的主要区别在于,第一种使用投影,第二种映射原始实体。对于仅是原始实体的一小部分的实体(例如列表的 dtos),只查询投影属性而不是完整实体(可能具有嵌套实体和您不需要的属性...)应该总是更快,然后映射到 dto。

    要结合两种解决方案(投影 + 通用解决方案)的优点,您可以自动创建投影表达式,缓存它们并在 Select(Expression<...>) 调用中使用它们,就像在您的原始解决方案。因此,所有映射只创建一次,您可以直接获取 dto,并且只查询必要的列。看看这篇文章和 cmets:Stop using AutoMapper in your Data Access Code.

    AutoMapper 也可以构建映射表达式,但它只会映射简单的属性(据我从源代码中理解)。使用自定义解决方案和一些“表达式魔术”,您还可以支持复杂的映射,然后通过实体框架将其转换为 sql:

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

    此代码here on github 是一个很好的起点。

    【讨论】:

      【解决方案3】:

      也许一些轻量级的 ORM 会有所帮助。例如DapperPetapoco。 他们可以使用 IL (Emit) 将 SQL 查询的结果绑定到动态或静态对象

      【讨论】:

        猜你喜欢
        • 2015-07-30
        • 1970-01-01
        • 2012-05-15
        • 1970-01-01
        • 2022-11-01
        • 2010-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多