.NET:是否有String.Format表单用于将对象属性的值插入字符串?

Geo*_*uer 8 .net string string.format

我认为这个问题的直接答案是"不",但我希望有人写了一个真正的简单库来做这件事(或者我可以做到......呃...)

让我用一个例子展示我正在寻找的东西.假设我有以下内容:

class Person {
  string Name {get; set;}
  int NumberOfCats {get; set;}
  DateTime TimeTheyWillDie {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

我希望能够做到这样的事情:

static void Main() {
  var p1 = new Person() {Name="John", NumberOfCats=0, TimeTheyWillDie=DateTime.Today};
  var p2 = new Person() {Name="Mary", NumberOfCats=50, TimeTheyWIllDie=DateTime.Max};

  var str = String.Format(

"{0:Name} has {0:NumberOfCats} cats and {1:Name} has {1:NumberOfCats} cats.  They will die {0:TimeTheyWillDie} and {1:TimeTheyWillDie} respectively
", p1, p2);

  Console.WriteLine(str);
}
Run Code Online (Sandbox Code Playgroud)

有没有人知道是否有这样的格式,或者有人写了一个库来做这件事?我知道它不应该太难,但我宁愿不重新实现轮子.

Mar*_*ett 9

编辑:您不必为每个对象实现IFormattable ......这将是一个PITA,严重限制,以及相当大的维护负担.只需使用Reflection和IFormatProvider与ICustomFormatter,它将适用于任何对象.String.Format有一个重载,可以将一个参数作为参数.

我以前从未想过这个,但你引起了我的兴趣 - 所以我不得不快速旋转一下.请注意,我选择允许将其他格式字符串传递给属性值,并且它仅适用于非索引和可访问的属性(尽管您可以轻松添加它).

public class ReflectionFormatProvider : IFormatProvider, ICustomFormatter {
    public object GetFormat(Type formatType) {
        return formatType == typeof(ICustomFormatter) ? this : null;
    }

    public string Format(string format, object arg, IFormatProvider formatProvider) {
        string[] formats = (format ?? string.Empty).Split(new char[] { ':' }, 2);
        string propertyName = formats[0].TrimEnd('}');
        string suffix = formats[0].Substring(propertyName.Length);
        string propertyFormat = formats.Length > 1 ? formats[1] : null;

        PropertyInfo pi = arg.GetType().GetProperty(propertyName);
        if (pi == null || pi.GetGetMethod() == null) {
            // Pass thru
            return (arg is IFormattable) ? 
                ((IFormattable)arg).ToString(format, formatProvider) 
                : arg.ToString();
        }

        object value = pi.GetGetMethod().Invoke(arg, null);
        return (propertyFormat == null) ? 
            (value ?? string.Empty).ToString() + suffix
            : string.Format("{0:" + propertyFormat + "}", value);
    }
}
Run Code Online (Sandbox Code Playgroud)

你稍微修改过的例子:

var p1 = new Person() {Name="John", NumberOfCats=0, TimeTheyWillDie=DateTime.Today};
var p2 = new Person() {Name="Mary", NumberOfCats=50, TimeTheyWillDie=DateTime.MaxValue};

var str = string.Format(
    new ReflectionFormatProvider(),
    @"{0:Name} has {0:NumberOfCats} cats and {1:Name} has {1:NumberOfCats} cats. 
    They will die {0:TimeTheyWillDie:MM/dd/yyyy} and {1:TimeTheyWillDie} respectively.
    This is a currency: {2:c2}.", 
    p1, 
    p2,
    8.50M
);

Console.WriteLine(str);
Run Code Online (Sandbox Code Playgroud)

输出:

John has 0 cats and Mary has 50 cats. 
They will die 12/10/2008 and 12/31/9999 11:59:59 PM respectively.
This is a currency: $8.50.
Run Code Online (Sandbox Code Playgroud)


Pao*_*sco 5

“:”后面的内容作为参数传递给类的 ToString 方法。
只需声明一个接受字符串的 ToString 方法,“Name”、“NumberOfCats”等将在该参数中传递。

编辑:您必须实现 System.IFormattable。这有效:

class Person : IFormattable
{
    public override string ToString()
    {
        return "Person";
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (format == "Name")
        {
            return "John";
        }
        if (format == "NumberOfCats")
        {
            return "12";
        }
        return "Unknown format string";
    }

}

class Program
{
    static void Main(string[] args)
    {
        Person p = new Person();
        Console.WriteLine(string.Format("Name = {0:Name}",p));
        Console.WriteLine(string.Format("NumberOfCats = {0:NumberOfCats}", p));
    }
}
Run Code Online (Sandbox Code Playgroud)