I want to use string.Format
with optional parameters
:
public static void Main(string[] args)
{
// Your code goes here
// Console.WriteLine(string.Format("{0} {1}", "a", "b"));
Console.WriteLine(string.Format("{0} {1}", "a"));
}
for exemple the parameter {1}
to be optional and to have a default value
Can you help me to do this?
It depends on what you mean by "optional parameter".
If you want to automatically replace null
with a default value, the easiest way to do that is to use the null coalescing operator inside the arguments:
String.Format("{0} {1}",
"a",
someNullableVariableContainingB ?? "default value");
If you want to reuse the same formatting string for multiple String.Format invocations, e.g.
var myFormatString = "{0} {1}";
var string1 = String.Format(myFormatString, "a", "b");
var string2 = String.Format(myFormatString, "a");
then you are out of luck: String.Format will throw an exception if too few arguments are provided, and there's no way to specify an "optional parameter" inside the format string. You will have to use something other than String.Format, for example, a custom method which replaces missing arguments with their intended default values.
This extension method is not limited to a fixed number of parameters. That is it will work with strings like "{0}"
, but also "{0} {1}"
, "{0} {1} {2}"
and so on.
The minor disadvantage is that first you give optional argument and then the non-optional. Should be the other way around but unfortunately the nature of the params
keyword prohibits that.
The major disadvantage is that it ignores the number in the curly braces (though the solution can be reworked to include that as well).
public static string FormatOpt(this string s, string optional, params string[] param)
{
StringBuilder result = new StringBuilder();
int index = 0;
bool opened = false;
Stack<string> stack = new Stack<string>(param.Reverse());
foreach(var c in s)
{
if (c == '{')
{
opened = true;
index = result.Length;
}
else if (opened && c == '}')
{
opened = false;
var p = stack.Count > 0 ? stack.Pop() : optional;
var lenToRem = result.Length - index;
result.Remove(index, lenToRem);
result.Append(p);
continue;
}
else if (opened && !Char.IsDigit(c))
{
opened = false;
}
result.Append(c);
}
return result.ToString();
}
And there are expected results:
string res1 = "result: {0}, {1}, {2}, {3}".FormatOpt("optional", "first param", "second param");
// result: first param, second param, optional, optional
string res2 = "result: {0}, {1}, {2}, {3}".FormatOpt("optional", "first param");
// result: first param, optional, optional, optional
string res3 = "result: {0}, {1}, {2}, {3}".FormatOpt("optional");
// result: optional, optional, optional, optional
private static Regex curlyBracketRegex = new Regex("\\{(.+?)\\}");
private static string OptionalFormat(string formatString, params object[] args)
{
var numberOfArguments = curlyBracketRegex.Matches(formatString).Count;
var missingArgumentCount = numberOfArguments - args.Length;
if (missingArgumentCount <= 0) //more argument or just enough
return string.Format(formatString, args);
args = args.Concat(Enumerable.Range(0, missingArgumentCount).Select(_ => string.Empty)).ToArray();
return string.Format(formatString, args);
}
This method above works with simple format strings. The regex detects the curly brackets. If the matches count is higher than the number of the passed args a new array will be created combining the original array with empty strings.
Example: OptionalFormat("{0}#{1}", "apple") //apple#
You could create an extension method:
public static string MyFormat(this string s, int i, params string[] args){
var t = new List<string>(args);
for(var c = t.Count; c < i; ++c)
t.Add(String.Empty); // or other default
return String.Format(s, t.ToArray());
}
and call:
"{0}:{1} - {2},{3},{4}".MyFormat(5, "ping", "fnord");
It does however force you to specify an arguments in order, so you cannot skip {3} if you want to set {4}. You could however add:
for(var x = 0; x < args.Count; ++x){
if(args[x] == null) args[x] = String.Empty;
and call:
"{0}:{1} - {2},{3},{4}".MyFormat(5, "ping", null, "pong");
to set {0} and {2}, but default {1}, {3} and {4} to String.Empty;
You could go for automagically determining the i, but it's so much easier like this.
来源:https://stackoverflow.com/questions/27363374/c-sharp-string-format-optional-parameters