使用反射有条件地循环通过属性

时间:2015-10-01 15:19:01

标签: c#

我正在使用网络服务向我返回JsonAddressModel,以换取我在不同地方申请中的string

我需要在表单的确认页面上将客户地址打印为连续的string

我最初编写了这个方法,它的目的是用逗号分隔每个属性并省略任何null属性,但这种方法效果很好但是肯定是非常重复的。

原创方法

public static string ConcatAddress(JsonAddressModel jsonAddressModel)
{
    StringBuilder builder = new StringBuilder();

    if (jsonAddressModel.saon.Replace(" ", "") != "" && jsonAddressModel != null)
        builder.Append(jsonAddressModel.saon + ", ");

    if (jsonAddressModel.paon != null)
        builder.Append(jsonAddressModel.paon + ", ");

    if (jsonAddressModel.thorofare != null)
        builder.Append(jsonAddressModel.thorofare + ", ");

    if (jsonAddressModel.dthorofare != null)
        builder.Append(jsonAddressModel.dthorofare + ", ");

    if (jsonAddressModel.posttown != null)
        builder.Append(jsonAddressModel.posttown + ", ");

    if (jsonAddressModel.county != null)
        builder.Append(jsonAddressModel.county + ", ");

    if (jsonAddressModel.postcode != null)
        builder.Append(jsonAddressModel.postcode);

    return builder.ToString();
}

经过测试后,我试图以更优雅的方式进行重构,并决定尝试使用反射来计算JsonAddressModel的属性,并使用foreach循环依次附加每个属性

新方法

public static string ConcatAddress(JsonAddressModel jsonAddressModel)
{
    StringBuilder builder = new StringBuilder();

    foreach (PropertyInfo prop in jsonAddressModel.GetType().GetProperties())
    {
        if (prop != null)
        {    
            builder.Append(prop.GetValue(jsonAddressModel, null) + ",");
        }
    }                
    return builder.ToString();
}

问题

虽然新方法现在附加了我想要显示的每个正确属性,例如saon / paon,thorofare等。它还附加了eastings,northings,uprn以及System.Runtime.Serialization.ExtensionDataObject之类的东西。显然我不希望在我的连接地址字符串中包含这些内容。

问题

有没有确切规定我允许在这里附加哪些属性?

我认为BindingFlags在我的实例中不起作用,因为如前所述,我从Web服务接收此模型,并且我想要和不想要的属性分别是{{1} }。

我考虑过创建一个数组但是我能看到的唯一名称相关字段是Private,它类似于SetMethod但是对于每个属性,我不完全确定如何抓住这个。

3 个答案:

答案 0 :(得分:2)

有可能通过反思做出你所要求的事情,但是你并没有提供任何关于你想要的项目之间差异的信息。包括和那些你没有。

但是,在这种情况下,您可以在保留重要部分(即确定哪些项目包含在输出中的部分)的同时消除代码中的重复,并且作为奖励,它会更有效率而不是使用反射。

    public static string ConcatAddress(JsonAddressModel jsonAddressModel)
    {
        var nonEmptyProperties = new [] {
            jsonAddressModel.saon,
            jsonAddressModel.paon,
            jsonAddressModel.thorofare,
            jsonAddressModel.dthorofare,
            jsonAddressModel.posttown,
            jsonAddressModel.county,
            jsonAddressModel.postcode,
        }.Where(s => !string.IsNullOrWhiteSpace(s));
        return string.Join(", ", nonEmptyProperties);
    }

答案 1 :(得分:2)

这是一个更通用的方法,您可以在函数调用中指定参数:

public string ConcatProperties<T>(T input, params Func<T, string>[] propertyDelegates)
{
    return string.Join(
        ",", 
        propertyDelegates
            .Select(p => p(input))
            .Where(s => !string.IsNullOrEmpty(s));
}

你这样使用它:

var concatenatedString = ConcatProperties(thingy,
    x => x.Foo,
    x => x.Bar,
    x => x.Wobble);

注意:这仅适用于字符串属性,对于您需要将属性转换为字符串的其他属性(例如x => x.Wibble.ToString()

答案 2 :(得分:0)

是的,Linq非常容易:

而不是直接使用

foreach (PropertyInfo prop in jsonAddressModel.GetType().GetProperties())
{
   // ...
}

你可以使用

var desiredProperties = new List<string>
{
    "saon",
    "paon"
};
IEnumerable<PropertyInfo> pis = jsonAddressModel.GetType().GetProperties();
var filteredPropertyInfos = pis.Where(pi => desiredProperties.Contains(pi.Name));

foreach (PropertyInfo prop in filteredPropertyInfos)
{
   // ...
}