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

时间:2011-11-22 11:48:21

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


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

该类的源代码如下:

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

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


谢谢,新泽西州

4 个答案:

答案 0 :(得分:3)

试试这个:

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)。

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

您应该将您的功能签名更改为以下转换器中的一点变化,我假设您无法传递源类型,否则您可以添加泛型参数作为函数的输入。

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

答案 3 :(得分:1)

根据要求,yaakov的答案对你的问题是正确的,我已经相应地投了赞成票。不过,我认为有更好的答案。

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

http://automapper.org/

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

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