自动确定 MaxLength 并将其用于填充

Automatically determine MaxLength and use it for padding

我有一个模型,其中包含这样定义的一堆字段:

public class Transaction
{
    public DateTime R03DateFrom { get; set; }
    public DateTime? R03DateTo { get; set; }
    [MaxLength(80)]
    public string R03Place { get; set; }
    [MaxLength(20)]
    public string R03Code { get; set; }
    // And so on....
}

在某个时候我需要将一些数据导出到固定宽度的文件,如果一个字符串的 MaxLength 为 x,那么在输出文件中它应该总是输出右填充最多 x 的空格字符。

我希望重新使用字符串的 MaxLength 始终在模型中定义这一事实,以便将此信息传递到导出。

目前,一个典型的导出行函数如下所示(ExDateTime 是一种将日期格式化为 yyyyMMddhhmm 格式的扩展方法):

    private string GetR03Row()
    {
        return GetRowCode() + "03" +
               R03DateFrom.ExDateTime() +
               R03DateTo.ExDateTime() +
               (R03Place??"").PadRight(80) +
               (R03Code??"").PadRight(20);
    }

我想更换线路

(R03Place??"").PadRight(80)

使用 MaxLength 属性的内容。

每个字符串都有一个 MaxLength。

更新:

我采纳了下面的建议并将其变成了扩展方法:

    public static string PadToMax<T>(this string source, string propName)
    {
        PropertyInfo[] props = typeof(T).GetProperties();
        var found = props.Where(m => m.Name.Equals(propName));

        if (!found.Any()) return source;

        var propertyInfo = found.First();
        var attrs = propertyInfo.GetCustomAttributes(false);

        if (!attrs.Any()) return source;

        foreach (var maxLengthAttribute in attrs.OfType<MaxLengthAttribute>())
        {
            return (source??"").PadRight(maxLengthAttribute.Length);
        }

        return source;
    }

这让我可以使用这个语法来实现我想要的:

// (R03Place??"").PadRight(80) turns into
R03Place.PadToMax<Transaction>(nameof(R03Place))

这很好。如果我可以更改扩展方法以某种方式计算出 "Transaction" 类型和源字符串变量的名称,我会很高兴。但是已经足够接近了。

可以将最大长度保存为私有字段吗?

public class Transaction
{
    private int maxLengthPlace = 80

    public DateTime R03DateFrom { get; set; }
    public DateTime? R03DateTo { get; set; }
    [MaxLength(maxLengthPlace)]
    public string R03Place { get; set; }
    [MaxLength(20)]
    public string R03Code { get; set; }
    // And so on....
}

然后再使用相同的字段?

(R03Place??"").PadRight(maxLengthPlace)

Olivier 的提议应该可行。

换个方式:

    private static void Main(string[] args)
    {
        var maxLength = GetMaxLengthAttributeValue<Transaction>("R03Place");
        Console.WriteLine("R03Place = {0}",maxLength);
        maxLength = GetMaxLengthAttributeValue<Transaction>("R03Code");
        Console.WriteLine("R03Place = {0}",maxLength);
        Console.ReadLine();
    }

    public static int? GetMaxLengthAttributeValue<T>(string propertyName)
    {
        PropertyInfo[] props = typeof (T).GetProperties();
        var found = props.Where(m => m.Name.Equals(propertyName));

        if (!found.Any()) return null;

        var propertyInfo = found.First();
        var attrs = propertyInfo.GetCustomAttributes(false);

        if (!attrs.Any()) return null;

        foreach (object attr in attrs)
        {
            MaxLengthAttribute maxLengthAttribute = attr as MaxLengthAttribute;
            if (maxLengthAttribute != null)
            {
                return maxLengthAttribute.Length;
            }
        }

        return null;
    }

将方法放在辅助程序中 class:

//You can use it as:    
(R03Place??"").PadRight(YourHelper.GetMaxLengthAttributeValue<Transaction>("R03Place").Value);

// with C# 6, you don't have to hard code the property name
  (R03Place??"").PadRight(YourHelper.GetMaxLengthAttributeValue<Transaction>(nameof(R03Place)).Value);