使用其他类的属性值创建类的对象列表的扩展方法

本文关键字:对象 列表 方法 创建 扩展 属性 其他 | 更新日期: 2023-09-27 18:15:20


我为IQueryable类创建了一个Extension方法,用于将泛型源类的列表转换为其他泛型目标类的列表(.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();
    }
}


这很好,
现在我唯一想知道的是-
是否可以跳过CCD_ 1参数,
如何从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>();


谢谢,NJ

使用其他类的属性值创建类的对象列表的扩展方法

试试这个:

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不同的类型(。

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

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

您应该按以下方式更改函数签名,并在转换器中稍作更改,我认为您不能传递源类型,否则您可以添加泛型参数作为函数的输入。

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();
       ....
    }
}

yaakov对您提出的问题的回答是正确的,因此我投了赞成票。不过,我认为还有更好的答案。

作为编写自己的映射反射代码的替代方案,可以考虑使用automapper。

http://automapper.org/

这是一个已经解决的问题,很多人都经过了很好的测试和使用,它有很多功能和灵活性,可以处理很多你可能没有考虑的边缘案例。我建议你去看看。

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