我认为这个问题的直接答案是'不',但我希望有人写了一个真正的简单库来做这件事(或者我可以做到......呃......)
让我通过一个例子展示我正在寻找的东西。 假设我有以下内容:
class Person {
string Name {get; set;}
int NumberOfCats {get; set;}
DateTime TimeTheyWillDie {get; set;}
}
我希望能够做到这样的事情:
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);
}
有没有人知道是否有这样做的格式,或者有人写了一个库来做吗?我知道它不应该太难,但我宁愿不再重新实现这个轮子。
答案 0 :(得分:9)
编辑:您不必为每个对象实施IFormattable ......这将是一个PITA,严重限制,并且相当大的维护负担。只需使用Reflection和带有ICustomFormatter的IFormatProvider,它就可以与任何对象一起使用。 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);
}
}
你的略微修改的例子:
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);
输出:
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.
答案 1 :(得分:4)
您可以覆盖您班级的ToString()。
好文章here
答案 2 :(得分:4)
将“:”作为参数传递给您班级的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));
}
}
答案 3 :(得分:2)
查看我的图书馆“Expansive”
在Nuget上:http://nuget.org/List/Packages/Expansive
在GitHub上:http://github.com/anderly/expansive
答案 4 :(得分:1)
我真的不明白这是怎么回事:
"{0:Name} has {0:NumberOfCats} cats and {1:Name} has {1:NumberOfCats} cats. They will die {0:TimeTheyWillDie} and {1:TimeTheyWillDie} respectively", p1, p2);
比这更好:
"{0} has {1} cats and {2} has {3} cats. They will die {4} and {5} respectively
", p1.Name, p1.NumberOfCats, p2.Name, p2.NumberOfCats, p1.TimeTheyWillDie, p2.TimeTheyWillDie);
事实上,由于你在第一篇文章中失去了智能感知帮助,不仅更容易失败,而且可能需要更长时间才能在IDE中编写。
如果你想做这样的事情,你总是可以为它做一个扩展方法。我敢打赌,这看起来像是一场噩梦。,
答案 5 :(得分:0)
许多人在Python世界中使用“someString%locals()”。你的建议虽然有一些与string.format有效的基本结合:
通常占位符表示法在冒号后面有字符串格式信息,而你想要进行属性访问。
占位符索引({0,{1等)通常引用params args中的numberes参数,但看起来你希望你的函数为每个传入的参数呈现整个字符串。他们应该连接吗?以字符串数组的形式返回?
所以你最终可能自己编写这个,在这种情况下你可以完全跳过索引表示法(所以{NumberOfCats}而不是{0:NumberOfCats},甚至使用属性名称后跟格式提供者{NumberOfCats:c}。从输入对象中消耗元数据不应该太难。
答案 6 :(得分:0)
Boo或Nemerle有类似的东西。我已经试着想出一个很好的简单方法来做几年了,没有简单的答案。
您可以做的最好的事情是为您提供自己的IFormatProvider,并手动解析输入(蹩脚的部分......)。
答案 7 :(得分:0)
如果你决定自己解析格式字符串,你应该考虑这个......:
Spring.NET项目在Spring.Core中有Spring.NET Expression Language。它允许您通过使用字符串指向属性来查询对象图。使用你的例子,你可以想象这样的事情:
var person = new Person { Name = "joe", Email = new Email { Address = "joe@joe.com" } };
var message = string.Format("{0}'s e-mail is {1}",
ExpressionEvaluator.GetValue(person, "Name"),
ExpressionEvaluator.GetValue(person, "Email.Address"));
(我可能不会存储这样的电子邮件,但我无法想出更好的信息)