Python-style string formatting for C#

[Jon Skeet][skeet] recently asked in one of [his posts][op]:

> it would be really nice to be able to write:
>
> `throw new IOException(“Expected to read {0} bytes but only {1} were available”, requiredSize, bytesRead);`

Which would do the same as

throw new IOException(String.Format(
“Expected to read {0} bytes but only {1} were available”,
requiredSize, bytesRead));

And it got me wondering about the String.Format method, and how much uglier it makes C# code to read than, say, the equivalent python code. Alongside each other;

// C#
string message = String.Format(
“Expected to read {0} bytes but only {1} were available”,
requiredSize, bytesRead);

// python
message = “Expected to read %s bytes but only %s were available” % (requiredSize, bytesRead)

I think I’d solve the problem, not by creating a new constructor for `IOException`, but by making String.Format part of the C# syntax. It works very nicely for python, and it’s such a common thing to do that I tink it would warrant a change to the language. Given how cumbersome String.Format is, it’s often shorter and clearer to use simple string concatenation. This makes things rather inconsistent.

Here’s what I came up with. It’s a ‘first draft’, and more for interest’s sake than as something I’d put into production.

Instead of passing an object array in as the values, I’m reading from the properties of an object. So you can do it with objects or tuples;

var person = new Person()
{
firstname=”Steve”,
secondname=”Cooper”
};

Then you can inject the tuple into a format string like this;

string message = “{firstname} {surname} says injecting properties is fun!”.ㄍ(person)
// message == “Steve Cooper says injecting properties is fun!”

So you’ll see this weird thing on the end of the format string that looks like a double-chevron. This is supposed to look like a double arrow, pushing values into the format string. In fact, it’s the [Bopomopho letter ‘G’][g] and therefore a perfectly normal C# method name.

Here’s the code for the double-chevron method. I say again, this is _just a proof of concept_, not production code. Use at your own peril. (In fact, don’t use. Write your own. It’ll be more solid.)

public static class StringFormatting
{
public static string ㄍ(this string format, object o)
{
var rx = new System.Text.RegularExpressions.Regex(@”{(?w+)}”);
var match = rx.Match(format);
while (match.Success)
{
string name = match.Groups[“name”].Value;
format = format
.Replace(“{“, “{{“)
.Replace(“}”, “}}”)
;
format = format.Replace(“{{” + name + “}}”, “{0}”);

object prop = o.GetType().GetProperty(name).GetValue(o, null);
format = string.Format(format, prop);
match = rx.Match(format);

}
return format;
}
}

[skeet]: http://msmvps.com/blogs/jon_skeet/default.aspx
[op]: http://msmvps.com/blogs/jon_skeet/archive/2009/01/23/quick-rant-why-isn-t-there-an-exception-string-params-object-constructor.aspx
[g]: http://www.alanwood.net/unicode/bopomofo.html

Advertisement

5 thoughts on “Python-style string formatting for C#

  1. You’ll want to have a look at this benchmarking article describing the same thing you want to do:

    http://haacked.com/archive/2009/01/04/fun-with-named-formats-string-parsing-and-edge-cases.aspx

    I’ve implemented Phil’s solution in my project; it works very nice and clarifies String.Format as you’d like to do, while eliminating the hit from regex.

    I like the use of the ㄍ character, I may give that a go (right now the extension method is just plainly named “Format”).

  2. @Charles

    Looks like the whole world decided to do it at the same time! 😉

    I had an even crazier idea using anonymous methods, doing something like this;

    "my name is {name}".<<(name=>"Steve")
    

    where the last bit is an anonymous method like Func<string,object>. I thought it was basically loony until I saw that someone else in Phil Haack’s comments had already done it. Nothing new under the sun’n all that…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s