首页 > 解决方案 > 仅在有值时才获取属性名称和值

问题描述

我正在尝试模拟一个 .csv 文件,其中属性名称列表作为标题行,后跟项目列表的实际属性列表。

目前,我让它工作,但现在只需要包含属性的标题和值,其中项目在 list 中的任何位置都有该属性的值。

这是我目前拥有的:

public static string LeadsToCSVString(List<Lead> leads)
{
    StringBuilder builder = new StringBuilder();
    PropertyInfo[] properties = typeof(Lead).GetProperties();
    builder.AppendLine(string.Join(",", properties.Select(x => x.Name)));

    foreach (Lead lead in leads)
    {
        builder.AppendLine(string.Join(",", properties.Select(x => x.GetValue(lead))));
    }

    return builder.ToString();
}

在哪里Lead

public class Lead
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool IsOk { get; set; }
}

不能保证所有属性值都具有值,List<Lead>甚至可能存在以下属性没有值的情况:

FirstName,LastName,IsOK
Joe,,false
Adam,,true

需要做的是只有属性具有实际值的标题值和行列值。如果我采用上面的示例列表,CSV 字符串将如下所示:

FirstName,IsOk
Joe,false
Adam,true

我怎样才能修改我的代码来做到这一点?

如果列表中的任何对象具有该属性的值,会发生什么情况的一些示例:

FirstName,LastName,IsOK
Joe,Dirt,
Adam,,true

FirstName,LastName,IsOK
,Dirt,
Adam,,true

标签: c#reflection

解决方案


假设“有一个值”意味着它的值不为空(仅适用于引用类型和 Nullable 值类型),您可以过滤掉列表中没有任何值的那些:

var filteredProps = properties.Where(p => leads.Any(l => p.GetValue(l) != null));

..然后使用filteredProps而不是properties

public static string LeadsToCSVString(List<Lead> leads)
{
    StringBuilder builder = new StringBuilder();
    PropertyInfo[] properties = typeof(Lead).GetProperties();

    var filteredProps = properties.Where(p => leads.Any(l => p.GetValue(l) != null));
    builder.AppendLine(string.Join(",", filteredProps.Select(x => x.Name)));

    foreach (Lead lead in leads)
    {
        builder.AppendLine(string.Join(",", filteredProps.Select(x => x.GetValue(lead))));
    }

    return builder.ToString();
}

或者为了避免调用GetValue()两次,您可以创建属性及其值的字典(或查找):

public static string LeadsToCSVString(List<Lead> leads)
{
    StringBuilder builder = new StringBuilder();
    PropertyInfo[] properties = typeof(Lead).GetProperties();

    var propsDictionary =
        properties.ToDictionary(p => p, p => leads.Select(l => p.GetValue(l)).ToArray())
        .Where(pair => pair.Value.Any(o => o != null))
        .ToDictionary(pair => pair.Key, pair => pair.Value);

    builder.AppendLine(string.Join(",", propsDictionary.Keys.Select(x => x.Name)));

    foreach (Lead lead in leads)
    {
        builder.AppendLine(
            string.Join(",", propsDictionary.Keys.Select(x => x.GetValue(lead))));
    }

    return builder.ToString();
}

推荐阅读