从 Linq 查询结果创建类实例

本文关键字:实例 创建 结果 Linq 查询 | 更新日期: 2023-09-27 18:31:20

我正在尝试从我的 Linq 查询结果创建一个类实例。 由于我必须为许多类执行此操作,因此我正在尝试找到最合适的快捷方式。 我想知道我是否可以缩短查询的"选择"部分。

我的班级:

public class current_control_id_class
{
    public string asset_class { get; set; }
    public string region_code { get; set; }
    public string instance_code { get; set; }
    public int sdi_control_id { get; set; }
    public int rows_loaded { get; set; }  
}

我的分配功能:

foreach (var results in query)
{
    foreach (PropertyInfo result in results.GetType().GetProperties())
    {
        string name = result.Name;
        foreach (PropertyInfo info in used.GetType().GetProperties())
        {
            if (result.Name == info.Name)
            {
                Console.WriteLine("Result {0} matches class {1} and the value is {2}", result.Name, info.Name, result.GetValue(results,null));
            }                        
        }
    }
}

我的查询(我知道这有效)

current_control_id_class used = new current_control_id_class();
var query =
    from result in t_sdi_current_control_id.AsQueryable()
    where result.asset_class == asset_class
    && result.region_code == region
    && result.instance_code == site
    select new current_control_id_class() { 
        rows_loaded = result.rows_loaded,
        sdi_control_id = result.sdi_control_id,
        asset_class = result.asset_class,
        hsbc_region_code = result.hsbc_region_code,
        hsbc_instance_code = result.hsbc_instance_code
    };

从 Linq 查询结果创建类实例

您可以使用 AutoMapper 将 t_sdi_current_control_id 的实例映射到current_control_id_class的实例:

首先初始化映射:

Mapper.CreateMap<t_sdi_current_control_id, current_control_id_class>();

然后使用它:

var query =
    from result in t_sdi_current_control_id.AsQueryable()
    where result.asset_class == asset_class
    && result.region_code == region
    && result.instance_code == site
    select Mapper.Map<current_control_id_class>(result);

如果您不想使用第三方库,这里有一些经过测试的代码可以为您执行此操作:

/// <summary>
/// Maps instances of <typeparam name="TSource"/> to new instances of
/// <typeparam name="TDestination"/> by copying across accessible public
/// instance properties whose names match.
/// </summary>
/// <remarks>
/// Internally uses a compiled Expression, so mapping should be quick at
/// the expense of <see cref="Mapper"/> initialisation.
/// </remarks>
public class Mapper<TSource, TDestination>
    where TDestination : new()
{
    readonly Func<TSource, TDestination> map;
    public Mapper()
    {
        this.map = GenerateMapping();
    }
    static Func<TSource, TDestination> GenerateMapping()
    {
        var sourceProperties = GetPublicInstancePropertiesWithAccessors<TSource>(property => property.GetGetMethod());
        var destinationProperties = GetPublicInstancePropertiesWithAccessors<TDestination>(property => property.GetSetMethod());
        var source = Expression.Parameter(typeof(TSource));
        var destination = Expression.Variable(typeof(TDestination));
        var copyPropertyValues = from sourceProperty in sourceProperties
                                 from destinationProperty in destinationProperties
                                 where sourceProperty.Name.Equals(destinationProperty.Name, StringComparison.Ordinal)
                                 select Expression.Assign(
                                     Expression.Property(destination, destinationProperty),
                                     Expression.Property(source, sourceProperty)
                                 );
        var variables = new[] { destination };
        var assignNewDestinationInstance = Expression.Assign(destination, Expression.New(typeof(TDestination)));
        var returnDestinationInstance = new Expression[] { destination };
        var statements =
            new[] { assignNewDestinationInstance }
            .Concat(copyPropertyValues)
            .Concat(returnDestinationInstance);
        var body = Expression.Block(variables, statements);
        var parameters = new[] { source };
        var method = Expression.Lambda<Func<TSource, TDestination>>(body, parameters);
        return method.Compile();
    }
    /// <summary>
    /// Gets public instance properties of <typeparamref name="T"/> that
    /// have accessible accessors defined by <paramref name="getAccessor"/>.
    /// </summary>
    static IEnumerable<PropertyInfo> GetPublicInstancePropertiesWithAccessors<T>(Func<PropertyInfo, MethodInfo> getAccessor)
    {
        var type = typeof(T);
        var publicInstanceProperties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
        return from property in publicInstanceProperties
               let accessor = getAccessor(property)
               where accessor != null
               select property;
    }
    public TDestination Map(TSource source)
    {
        return map(source);
    }
}

像这样使用它:

//Keep this around so it gets re-used.
var mapper = new Mapper<t_sdi_current_control_id, current_control_id_class>();
var result = mapper.Map(value);