C# 是否可以创建扩展方法来格式化字符串?

C# 是否可以创建扩展方法来格式化字符串?,c#,formatting,extension-methods,C#,Formatting,Extension Methods,问题很简单。如何在C#中格式化字符串?这样: string.Format("string goes here with placeholders like {0} {1}", firstName, lastName); 现在,是否可以创建一个扩展方法来这样做 "string goes here {0} {1}".Format(firstName, lastName); 就这些。是的 public static string Format(this string str, string f

问题很简单。如何在C#中格式化字符串?这样:

 string.Format("string goes here with placeholders like {0} {1}", firstName, lastName);
现在,是否可以创建一个扩展方法来这样做

 "string goes here {0} {1}".Format(firstName, lastName);
就这些。

是的

public static string Format(this string str, string firstItem, string secondItem)
{
    return string.Format(str, firstItem, secondItem);
}

顺便说一句,此方法必须属于
公共
静态
类。

是的,您可以。当然,为了简洁起见,您总是希望验证源代码是否不为null。[更新]结果表明,即使您可以模拟1、2和3个参数的string.Format重载,但在幕后,1、2和3个参数的string.Format()重载仍然使用varg list重载。。。因此,删除了重载

public static class FormatExtension
{
    public static string Format(this string source, params object[] args)
    {
        return string.Format(source, args);
    }
}
顺便说一句,虽然我们表明这是可能的,但要小心扩展。这里的主要问题是.Format()实际上只对具有格式参数的字符串有意义。这使得使用string.Format()更为清晰,因为显然,参数是Format()想要的,并且应该采用正确的形式。但是,将.Format()作为扩展方法可能会失去一些意义,因为它将出现在任何字符串上,而不管格式化是否真正有效。只是一个小问题。

是的,有可能:

public static class StringFormatExtensions {
  public static string Format(this string formatStr, params object[] args) {
    return string.Format(formatStr, args);
  }
}
public static class Extensions
{
    public static string Format(this string str, params object[] args)
    {
        return String.Format(str, args);
    }
}
最好为一个和两个参数的情况添加重载

不过,总的来说,我认为这没有多大价值。

当然

public static class StringExtensions
{
    public static string FormatThis(this string format, params object[] args)
    {
        return string.Format(format, args);
    }
}

是的,你可以。但它将解决什么目的呢

嗯,这比看起来要复杂得多。其他人说这是可能的,我不怀疑他们,但在Mono中似乎不是这样

在这里,
Format()
方法的标准重载似乎优先于名称解析过程,编译失败,因为静态方法最终会在对象实例上被调用,这是非法的

鉴于此代码:

public static class Extensions
{
    public static string Format(this string str, params object[] args)
    {
        return String.Format(str, args);
    }
}

class Program
{
    public static void Main()
    {
        Console.WriteLine("string goes here {0} {1}".Format("foo", "bar"));
    }
}
Mono编译器(mcs 2.10.2.0)回复如下:

foo.cs(15,54):错误CS0176:静态 成员'string.Format(string,object)' 无法使用实例访问 引用,使用类型名称限定它 反而


当然,如果扩展方法没有命名为
Format()
,那么上面的代码会编译得很干净,但您可能确实想使用该名称。如果是这种情况,那么这是不可能的,或者至少在.NET平台的所有实现上是不可能的。

您应该始终将
IFormatProvider
传递给
String.Format
,例如
CultureInfo.InvariantCulture

我喜欢使用这组扩展方法:

public static class GlobalizedFormatting
{
    public static string Format(this string format, IFormatProvider provider, params object[] args)
    {
        return String.Format(provider, format, args);
    }

    public static string FormatInvariant(this string format, params object[] args)
    {
        return String.Format(CultureInfo.InvariantCulture, format, args);
    }

    public static string FormatCurrent(this string format, params object[] args)
    {
        return String.Format(CultureInfo.CurrentCulture, format, args);
    }
}
用法:

"{0} {1} {2}".Format(CultureInfo.InvariantCulture, "A", "B", "C");

"{0} {1} {2}".FormatInvariant("A", "B", "C");

"{0} {1} {2}".FormatCurrent("A", "B", "C");
是的,有可能:

public static class StringFormatExtensions {
  public static string Format(this string formatStr, params object[] args) {
    return string.Format(formatStr, args);
  }
}
public static class Extensions
{
    public static string Format(this string str, params object[] args)
    {
        return String.Format(str, args);
    }
}
并应按以下方式使用:

Console.WriteLine("format string {0} {1}".Format((object)"foo", "bar"));

是的,正如上面每个人所说。 但新的首选方式应该是:

$"string goes here {firstName} {lastName}";


是的,我当然试过了,但我做不到;)展示你的努力。显示您遇到的问题。这些问题似乎暗示您没有尝试编写自己的扩展方法。扩展方法在编程中非常酷、整洁、干净和方便。这只是一种编码风格。此处不寻求技术优势。:)其目的是将要格式化的操作数放在进行格式化的操作之前。您可能会问为什么我们使用
list.Where()
而不是
Enumerable.Where(list)
。所以你的意思是我们应该摆脱框架中的所有静态方法,只为用户喜欢这样写的目的而扩展它们。@Kirk Woll+1这正是我编写90%扩展方法的原因,我创建的扩展方法是为了帮助创建纯文本英语可读的DSL。|@hungryMind ALL是一个很强的词(如果愿意,有时甚至不能使用扩展方法),但是对于几乎所有的密集用途,如果静态方法是公共的,那么此时静态方法很容易成为代码气味。我的代码中的任何公共静态方法几乎肯定是一种扩展方法。在一些流畅的接口DSL中也有一些明显的例外,比如根对象。@hungryMind:“同一字符串的三个副本”?你在说什么?字符串是引用类型,在方法调用时不会被“复制”。Hmmm,也不知道为什么。真奇怪。也许是因为有人点击错误?也许是因为我的回答不够彻底?简单操作的答案是否需要一个完整的答案?它实际上被否决了,因为它不起作用-编译器在决定调用哪个方法时优先使用静态
String.Format
方法,这会导致编译器错误:
成员的String.Format(String,object)'无法使用实例引用访问;改为使用类型名称限定它
这对于所显示的OP(2个参数)是正确的。用户可以学习并推断其余内容。为什么投反对票?我不知道,但我会假设时间,因为这几乎是答案的精确副本。。。事实上,你的答案看起来是第一位的,我非常困惑。我在投票。我肯定我是第一个来这里的,真的@杰姆斯的回答是最完整的,但我首先在这里:)它也很难,因为有时你在输入答案的中间,有人先进来,但你不知道,直到你提交。这个方法将不编译,除非,当然,第一个名字和姓氏是全球声明!然后它会忽略传递到方法中的值。我在其中看到了很多值。通常我首先输入的是字符串。然后,在结束之前的某个时间,我意识到我将要在中替换一些值。我不必回到开头,将其全部包装在
string.Format
I中,而是在键入时完成字符串,包括所有替换字符,然后对其调用扩展方法。在我看来,这是一个更加自然的工作流程。这是一个品味的问题。我自己为string.IsNullOrEmpty实现了一个类似的方法,所以我猜这个值在旁观者眼里。如果我们将扩展方法命名为Format,编译器会说Format方法无法通过实例访问,我们应该使用类型