0

I have the following variable:

var setting = 
$@"worker_processes     {{0}};
worker_rlimit_nofile    {{1}};
error_log               logs/{{2}} {{3}};

events
{{
    worker_connections {{4}};
    multi_accept {{5}};
}}";

When I do the following String.Format() operation on it:

return string.Format(setting,
    this.worker_processes,
    this.worker_rlimit_nofile,
    this.error_log_file,
    this.error_log_level,
    this.worker_connections
    this.multi_accept ? "on" : "off");

I get the following error: Input string was not in a correct format.

Any ideas?


EDIT - Fixed

Thanks to Jon Skeet, I have arrived at this solution without using String.Format():

return 
$@"worker_processes         { this.worker_processes };
    worker_rlimit_nofile    { this.worker_rlimit_nofile };
    error_log               logs/{ this.error_log_file } { this.error_log_level };

    events
    {{
        worker_connections { this.worker_connections };
        multi_accept { (this.multi_accept ? "on" : "off") };
    }}";
Latheesan
  • 23,247
  • 32
  • 107
  • 201
  • 4
    If you're using C# 5.0 (as per your tag) `$@` shouldn't work at all - and it's not clear why you're trying to use it anyway. What are you actually trying to achieve? – Jon Skeet Sep 04 '15 at 16:00
  • Side note: there are 6 placeholders and 4 arguments... (That should give different error - so assuming that is copy-paste error). – Alexei Levenkov Sep 04 '15 at 16:03
  • @JonSkeet Sorry i meant to say I am using C# 4.5. I have a variable which holds a "Template" for a nginx config file. Then I want to replace the placeholders with values from a setting. – Latheesan Sep 04 '15 at 16:04
  • @AlexeiLevenkov - This was a cut-down version of my actual code, I will correct post now. – Latheesan Sep 04 '15 at 16:05
  • There's no such thing as C# 4.5. There's C# 1.0, C# 1.2, C# 2.0, C# 3.0, C# 4.0, C# 5.0 and C# 6.0. You may be using .NET 4.5... – Jon Skeet Sep 04 '15 at 16:07
  • There is no C# 4.5 - there is .Net 4.5, but C# itself has versions like 4 (very old), 5 (VS 2012/2013) and 6 (VS 2015) - http://stackoverflow.com/questions/247621/what-are-the-correct-version-numbers-for-c. – Alexei Levenkov Sep 04 '15 at 16:07
  • @JonSkeet - sorry I have removed the tag to avoid confusion. I am using `.NET Framework 4.5` (according to VS2015). I am able to use `var setting = $@"...";` - the program compiles. – Latheesan Sep 04 '15 at 16:10
  • 1
    @Latheesan: Right, you're using C# 6. The version of .NET is *mostly* irrelevant there (it affects whether FormattableString is available, but not whether you can use string interpolation at all.) – Jon Skeet Sep 04 '15 at 16:13

2 Answers2

4

It's unclear exactly what's going on as there's version confusion, but I suspect you just want:

var setting = 
@"worker_processes     {0};
worker_rlimit_nofile    {1};
error_log               logs/{2} {3};

events
{{
    worker_connections {4};
    multi_accept {5};
}}";

Now the braces for the events block will still be escaped, but the rest will be treated as format specifiers.

Here's a full example:

using System;

class Test
{
    static void Main(string[] args)
    {
        var setting = 
@"worker_processes     {0};
worker_rlimit_nofile    {1};
error_log               logs/{2} {3};

events
{{
    worker_connections {4};
    multi_accept {5};
}}";
        string text = string.Format(setting, 10, true, "log.txt", "debug", 20, false);
        Console.WriteLine(text);
    }
}

Output:

worker_processes     10;
worker_rlimit_nofile    True;
error_log               logs/log.txt debug;

events
{
    worker_connections 20;
    multi_accept False;
}

Or using string interpolation from C# 6:

    return $@"worker_processes     {worker_processes};
worker_rlimit_nofile    {worker_rlimit_nofile};
error_log               logs/{error_log_file} {error_log_level};

events
{{
    worker_connections {worker_connections};
    multi_accept {multi_accept};
}}";
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • using `string interpolation from C# 6`, how can I handle conditional values (like in my example: `this.multi_accept ? "on" : "off"`? Will this work: `return $@"multi_accept {multi_accept ? "on" : "off"};";`? Or is there a different syntax for that? – Latheesan Sep 04 '15 at 16:17
  • 1
    @Latheesan: If you had constants for "on" and "off" you could use `{multi_accept ? On : Off}` but I haven't found a way of including double quotes yet. As an aside, it would be a good idea to start following .NET naming conventions - `multiAccept` etc. – Jon Skeet Sep 04 '15 at 16:18
  • I found a solution to using double quotes in string interpolation like this (using parenthesis) : `return $@"multi_accept { (multi_accept ? "On" : "Off") };";` – Latheesan Sep 04 '15 at 16:27
2

using $ activates string interpolation, which allows a string to be autoformatted according to local variables. If you want to use numeric indecies and string.Format, don't use the interpolation. Because of the interpolation, the double braces around events are escaping to single braces, which then are seen byFormat` as a format specifier, but have an invalid syntax. IF you must use the interpolation, escape these braces again (making them quadruple)

Also note that the doble braces escapes out of the format specifier, so you'll need to scrape all but the braces under "events" or they'll come back as {0}, {1}, ect in the result string.

Finally, note that you only have 4 objects being passed into Format - since your specifiers go up to 5, you'll need 6 objects or you'll run into more exceptions.

David
  • 10,458
  • 1
  • 28
  • 40