反思在WCF中制作DTO对象

时间:2012-05-17 12:44:47

标签: .net performance entity-framework reflection dto

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

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

            }).ToList();

另一位程序员在构建WCF服务时使用Reflection编写了一个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。

有人可以帮我解释一下。感谢

3 个答案:

答案 0 :(得分:3)

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

显然,与基于基本反射的映射器相比,它们使内部更复杂(它们仍然非常易于使用),但通常情况下,优化速度会增加复杂性。

我的意见是你应该使用其中一个(优秀的)开源库,作者花了很多时间考虑很多像你一样的问题。

答案 1 :(得分:1)

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

要结合两种解决方案(投影+通用解决方案)的优点,您可以自动创建投影表达式,缓存它们并在选择(表达式&lt; ...&gt;)调用中使用它们你最初的解决方案所以所有映射只创建一次,直接得到你的dtos,只查询必要的列。请查看本文和评论:Stop using AutoMapper in your Data Access Code

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

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

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

答案 2 :(得分:0)

也许一些轻量级的ORM会有所帮助。例如DapperPetapoco。 他们可以使用IL(Emit)

将SQL查询的结果绑定到动态或静态对象