String.Format扩展方法

7

我有:

public static string Format(this string text, params object[] args)
{
   return string.Format(text, args);
}

所以我可以做:

"blablabla {0}".Format(variable1);

这个好吗?能不能更短?我希望字符串的构建可以无缝进行,就像写文本一样,不需要担心参数和其他东西。

// bad
return "date: " + DateTime.Now.ToString("dd.MM.yyyy") + "\ntime: " + DateTime.Now.ToString("mm:HH:ss") + "\nuser: " + _user + " (" + _status + ")";

// better, but you have to deal with order of {0}...{n} and order of parameters
return string.Format("date: {0}\ntime: {1}\user: {2} ({3})", ...);

// ideal
return "date: {DateTime.Now{dd:MM:yyyy}}\ntime: {...}\nuser: {_user} ({_status})";

我发现这个想法的预期输出非常令人困惑。 - Steve
“这是好的/不好的吗?”:你正在寻求意见,这在[SO]上是不相关的话题。 - Richard
@Richard,这只是我问的几个问题中的一个 =P - Sinatr
有两个问题,另一个是“它能变得更短吗”,如果“它”不已经是一个一行函数体,这可能是一个合理的问题。 - Richard
4个回答

3

嗯,唯一不好的事情是,只有一个params object[]方法会强制每次调用时额外分配一个数组。

您可能会注意到,string.Format有一系列重载,用于处理低数量的参数(这些非常常用)- 我建议复制它们。

您的“理想”情况可以通过重新编写string.Format方法来实现,但您需要传入值,即:

return "date: {date}\ntime: {...}\nuser: {_user} ({_status})"
     .Format(new { date = DateTime.Now, _user, _status });

(并使用您自己的定制格式方法,或者像这样的方法)- 但请注意,这会强制每次调用时创建一个新的对象实例。
实际上,有一段时间mono编译器有一个实验标志可以直接启用此功能。我不知道它是否被维护。

把我的标识符放入字符串中,然后用我需要的值替换它们,这是一个很酷的想法。谢谢! - Sinatr

3

我也使用类似的扩展方法,并且我喜欢它,我在扩展方法中指定了区域信息,在我的情况下是固定的系统。

public static string Format(this string formatTemplate, params object[] args)
{
   return string.Format(SysSettings.CultureInfo, formatTemplate, args);
}

用途:

return "date: {0:dd.MM.yyyy}\ntime: {1:mm:HH:ss}\nuser: {2} ({3})".Format(DateTime.Now, DateTime.Now, _user, _status);

很棒的文化理念,谢谢。当使用 doublefloat 时,我被迫使用中性文化来表示小数点,但是当使用 int 时从未这样做过。有了扩展方法,我可以一次性解决所有问题! - Sinatr
如果你尝试传递两个参数并且第一个参数是一个字符串,这将导致编译错误。例如"{0} - {1}".Format("example", 1);,因为它将匹配String.Format静态签名而不是扩展。 - GP89

3
这不完全符合您的理想,但类似这样的东西可能适合您:
public static class Extensions
{
    public static string Format(this object data, string format)
    {
        var values = new List<object>();
        var type = data.GetType();
        format = Regex.Replace(format, @"(^|[^{])\{([^{}]+)\}([^}]|$)", x =>
        {
            var keyValues = Regex.Split(x.Groups[2].Value,
                                        "^([^:]+):?(.*)$")
                                    .Where(y => !string.IsNullOrEmpty(y));

            var key = keyValues.ElementAt(0);
            var valueFormat = keyValues.Count() > 1 ?
                                ":" + keyValues.ElementAt(1) :
                                string.Empty;


            var value = GetValue(key, data, type);

            values.Add(value);
            return string.Format("{0}{{{1}{2}}}{3}", 
                                    x.Groups[1].Value, 
                                    values.Count - 1, 
                                    valueFormat, 
                                    x.Groups[3].Value);
        });


        return string.Format(format, values.ToArray());
    }

    private static object GetValue(string name, object data, Type type)
    {
        var info = type.GetProperty(name);
        return info.GetValue(data, new object[0]);
    }
}

这将使您能够在任何对象上进行此类格式设置:
new {Person = "Me", Location = "On holiday"}
    .Format("{Person} is currently {Location}");

它还可以让您添加一些格式:

new {Person = "Me", Until = new DateTime(2013,8,1)}
    .Format("{Person} is away until {Until:yyyy-MM-dd});

对你来说这个怎么样?我相信代码在效率方面可以改进,但功能是正常的!


你的想法是在调用Format之前生成args数组,并将变量的名称放入格式字符串中,而不是{0},我认为这很酷。谢谢。 - Sinatr
是的,除非Format扩展方法是在对象而不是数组上调用。 在我的例子中,这是一个匿名类型的实例,但实际上它可以是任何对象,例如域对象:(例如:var person = new Person(“Aaron”,“Janes”); person.Format(“{ LastName},{ FirstName}”);) - Aaron Janes
目前我编写的扩展方法不支持索引属性,因此以下代码将无法正常工作:new { Items = new [] {"One", "Two"} }.Format("First item: {Items[0]}"); 但是添加索引器支持应该相对容易。 - Aaron Janes

1

如果你独自编码,那就要看情况了。但如果是团队协作,这个想法就不太好,因为每个人都得学习这种方法。

另一个问题是,在字符串的Format中,如果意外包含了带有错误索引的大括号,比如{1}而不是{2},那么这个坏字符串就会导致整个应用程序崩溃。我曾经在我的日志记录中使用过类似的方法,不得不使用try-catch来处理FormatExceptions异常。


如果我在扩展方法中放置try/catch并提供其他方式来指示编程错误(例如,通过在字符串末尾添加类似于“天哪,参数{10}丢失”的内容),那么扩展方法就是一个很大的优势(因此我不必为每个格式重复try/catch)。每个团队都有自己的“样式”或常见情况的通用解决方案。如果您对语法感到困惑-您可以直接在Visual Studio中快速查看它是什么。所以我认为这里没有大问题。 - Sinatr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接