【问题标题】:Extension method to create list of objects of a class using property values of other class使用其他类的属性值创建类的对象列表的扩展方法
【发布时间】:2011-11-22 11:48:20
【问题描述】:


我为 IQueryable 类创建了一个扩展方法,将通用源类的列表转换为其他通用目标类的列表,(.net3.5)
我正在使用反射从源对象值中获取属性并将其分配给目标对象。

该类的源码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;

namespace System.Linq
{
    public static class QueryableExtensions
    {
        public static IQueryable<TDest> ToDTO<TDest>(this IQueryable<TSource> source)//getting error on this line
        {
            return DTOTranslator<TDest>.ConvertToDTO<TDest>(source);
        }
    }

    public class DTOTranslator<TSource>
    {
        public static IQueryable<TDest> ConvertToDTO<TDest>(IQueryable<TSource> source)
        {
            List<TDest> destinationList = new List<TDest>();
            List<TSource> sourceList = source.ToList<TSource>();

            var sourceType = typeof(TSource);
            var destType = typeof(TDest);
            foreach (TSource sourceElement in sourceList)
            {
                TDest destElement = Activator.CreateInstance<TDest>();
                //Get all properties from the object 
                PropertyInfo[] sourceProperties = typeof(TSource).GetProperties();
                foreach (PropertyInfo sourceProperty in sourceProperties)
                {
                    //and assign value to each propery according to property name.
                    PropertyInfo destProperty = destType.GetProperty(sourceProperty.Name);
                    destProperty.SetValue(destElement, sourceProperty.GetValue(sourceElement, null), null);
                    destinationList.Add(destElement);
                }
            }

            return destinationList.AsQueryable();
        }
    }
}



但是在编译时我在第 12 行收到错误:

The type or namespace name 'TSource' could not be found (are you missing a using directive or an assembly reference?)



更新:
感谢大家的回复。
现在我已将我的课程更新如下:

public static class QueryableExtensions
{
    public static IQueryable<TDest> ToDTO<TSource, TDest>(this IQueryable<TSource> source)
    {
        List<TDest> destinationList = new List<TDest>();
        List<TSource> sourceList = source.ToList<TSource>();

        var sourceType = typeof(TSource);
        var destType = typeof(TDest);
        foreach (TSource sourceElement in sourceList)
        {
            TDest destElement = Activator.CreateInstance<TDest>();
            //Get all properties from the object 
            PropertyInfo[] sourceProperties = typeof(TSource).GetProperties();
            foreach (PropertyInfo sourceProperty in sourceProperties)
            {
                //and assign value to each propery according to property name.
                PropertyInfo destProperty = destType.GetProperty(sourceProperty.Name);
                destProperty.SetValue(destElement, sourceProperty.GetValue(sourceElement, null), null);
                destinationList.Add(destElement);
            }
        }

        return destinationList.AsQueryable();
    }
}


这很好用,
现在我唯一想知道的是-
是否可以跳过&lt;TSource&gt; 参数,
如何从 IQueryable 的元素类型中读取它并定义它的对象? 我的意思是目前我将该方法称为

IQueryable<CATEGORY_DTO> dtos = (from p in new MyEntities().CATEGORY select p).ToDTO<CATEGORY, CATEGORY_DTO>();

我想称之为

IQueryable<CATEGORY_DTO> dtos = (from p in new MyEntities().CATEGORY select p).ToDTO<CATEGORY_DTO>();


谢谢,新泽西

【问题讨论】:

    标签: c# .net asp.net-3.5


    【解决方案1】:

    试试这个:

    public static class QueryableExtensions
    {
        public static IQueryable<TDest> ToDTO<TDest, TSource>(this IQueryable<TSource> source)
        {
            return DTOTranslator<TSource>.ConvertToDTO<TDest>(source);
        }
    }
    

    另外,ToDTO 方法还引用了TSource 泛型类型(否则你怎么能引用作为参数 - 这导致了原始错误),并且这个泛型类型在构造函数中给出DTOTranslator(因为在构造函数中使用TDest是错误的,因为构造函数本身需要的泛型类型的定义是TSource,它与TDest是不同的类型)。

    【讨论】:

      【解决方案2】:

      你需要声明两个类型参数:

      public static IQueryable<TDest> ToDTO<TSource, TDest>(this IQueryable<TSource> source)
      

      【讨论】:

      • 感谢您的回复,但是否可以获取 IQueryable 列表中的对象类型,因为我只想传递目标类型参数?
      • 这不会编译,因为 DTOTranslator 构造函数需要与 ConvertToDTO 方法的签名中使用的不同的泛型类型 (TSource)。
      • @NitinJS:你可以把 TDest 参数放在类而不是方法上,然后编译器可以使用类型推断来获取 TSource 的类型,而无需指定它。
      【解决方案3】:

      您应该如下更改函数签名并在转换器中进行一些更改,我假设您不能传递源类型,否则您可以将泛型参数添加为函数的输入。

      public static IQueryable<TDest> ToDTO<TDest>(this IQueryable source)
      {
         return DTOTranslator<TDest>.ConvertToDTO<TDest>(source);
      }
      
      public static IQueryable<TDest> ConvertToDTO<TDest>(IQueryable source)
      {
          Type sourceType = null;
          ....
          foreach(var item in source)
          {
             // find source type is it not found till now
             if (sourceType == null)
               sourceType = item.GetType();
             ....
          }
      }
      

      【讨论】:

        【解决方案4】:

        yaakov 的回答对您提出的问题是正确的,我对此表示赞同。不过,我认为有更好的答案。

        作为您在此处编写自己的映射反射代码的替代方法,请考虑使用 automapper。

        http://automapper.org/

        这是一个已经解决的问题,并且经过了很多人的充分测试和使用,它具有很多功能和灵活性,并且可以处理很多您可能没有考虑的边缘情况。我建议你检查一下。

        还想补充一点,您使用 system.linq 命名空间有点奇怪。 system 应该为框架类库中的东西保留,我建议您使用自己的命名空间。这并不重要,但我认为使用类似的东西会让你和你的代码的任何其他用户感到困惑。

        【讨论】:

          猜你喜欢
          • 2019-01-29
          • 1970-01-01
          • 1970-01-01
          • 2012-01-17
          • 2016-11-30
          • 1970-01-01
          • 2013-07-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多