You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何传递自定义LambdaExpression?DataTable转换扩展方法场景

在C#中通过Lambda表达式筛选类属性以转换为DataTable

我来帮你解决这个问题——要实现通过Lambda表达式指定不需要添加到DataTable的类属性,我们可以从扩展方法的参数设计和Lambda解析两方面入手,下面分步骤说明:

1. 设计支持Lambda筛选的扩展方法

首先我们需要调整ConvertToDataTable2方法的参数,允许传入一组Lambda表达式来指定要排除的属性。这里需要处理值类型属性的装箱问题(比如int类型的属性会被包装为UnaryExpression),确保能正确提取属性名称。

扩展方法实现代码

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

public static class ObjectExtensions
{
    public static DataTable ConvertToDataTable2<T>(this T obj, params Expression<Func<T, object>>[] excludedProperties)
    {
        var dataTable = new DataTable();
        var type = typeof(T);
        
        // 收集所有要排除的属性名称
        var excludedNames = new HashSet<string>();
        foreach (var expr in excludedProperties)
        {
            switch (expr.Body)
            {
                // 引用类型属性的Lambda表达式
                case MemberExpression memberExpr:
                    excludedNames.Add(memberExpr.Member.Name);
                    break;
                // 值类型属性会被装箱,需要拆箱获取MemberExpression
                case UnaryExpression unaryExpr when unaryExpr.Operand is MemberExpression memberExpr:
                    excludedNames.Add(memberExpr.Member.Name);
                    break;
            }
        }
        
        // 添加未被排除的属性作为DataTable列
        foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            if (!excludedNames.Contains(prop.Name))
            {
                // 处理可空类型,获取底层类型
                var columnType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
                dataTable.Columns.Add(prop.Name, columnType);
            }
        }
        
        // 填充数据行
        var row = dataTable.NewRow();
        foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            if (!excludedNames.Contains(prop.Name))
            {
                row[prop.Name] = prop.GetValue(obj) ?? DBNull.Value;
            }
        }
        dataTable.Rows.Add(row);
        
        return dataTable;
    }
}

2. 使用Lambda表达式调用扩展方法

现在你可以直接传入Lambda表达式,指定哪些属性不需要被添加到DataTable中。比如如果你想排除ReasonCode和Description属性,调用代码如下:

class Program
{
    static void Main(string[] args)
    {
        CancelMaintenance cm = new CancelMaintenance();
        cm.UserID = 1;
        cm.CancelReasonCodeID = 2;
        cm.CancelRefund = "C";
        cm.Description = "test";
        cm.ReasonCode = "TestCode";
        
        // 传入要排除的属性的Lambda表达式
        DataTable dt = cm.ConvertToDataTable2(x => x.ReasonCode, x => x.Description);
    }
}

public class CancelMaintenance
{
    public int UserID { get; set; }
    public int CancelReasonCodeID { get; set; }
    public string CancelRefund { get; set; }
    public string Description { get; set; }
    public string ReasonCode { get; set; }
}

3. 更灵活的筛选方式(可选)

如果你需要更复杂的筛选逻辑(比如只保留特定类型的属性,或者按属性名称前缀筛选),可以将扩展方法的参数改为Func<PropertyInfo, bool>,直接传入属性判断逻辑:

扩展方法重载版本

public static DataTable ConvertToDataTable2<T>(this T obj, Func<PropertyInfo, bool> includePredicate)
{
    var dataTable = new DataTable();
    var type = typeof(T);
    
    foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        if (includePredicate(prop))
        {
            var columnType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
            dataTable.Columns.Add(prop.Name, columnType);
        }
    }
    
    var row = dataTable.NewRow();
    foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        if (includePredicate(prop))
        {
            row[prop.Name] = prop.GetValue(obj) ?? DBNull.Value;
        }
    }
    dataTable.Rows.Add(row);
    
    return dataTable;
}

调用示例(只保留指定属性)

// 只保留UserID、CancelReasonCodeID、CancelRefund三个属性
DataTable dt = cm.ConvertToDataTable2(prop => 
    prop.Name == nameof(CancelMaintenance.UserID) ||
    prop.Name == nameof(CancelMaintenance.CancelReasonCodeID) ||
    prop.Name == nameof(CancelMaintenance.CancelRefund));

内容的提问来源于stack exchange,提问作者Neeraj Kumar Gupta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:06:13