按照格式化字串功能的進化,本文討論下string.format(),c# 6版本的字串內插及c#10版本的字串內插優化。
實現格式化字串有多種方法,如可以使用簡單的字串相加,但是這種方式可讀性較差。
如果需要對齊引數,可以在{}內使用','指定對齊方式。
如果需要格式化引數,可以在{}內使用':'指定格式化方式,format()方法會檢查引數是否實現了iformattable,是則呼叫iformattable.tostring(string format, iformatprovider formatprovider)方法獲取格式化後的字串進行拼接。因此,如果想自定義型別格式化形式,需實現iformattable介面。當然也可以實現iformatprovider和icustomformatter介面,並將iformatprovider的實現類作為引數傳入。
public static string format(string format, object arg0);
public static string format(string format, object arg0, object arg1);
public static string format(string format, object arg0, object arg1, object arg2);
public static string format(string format, params object args);
public static string format(iformatprovider provider, string format, object arg0);
public static string format(iformatprovider provider, string format, object arg0, object arg1);
public static string format(iformatprovider provider, string format, object arg0, object arg1, object arg2);
public static string format(iformatprovider provider, string format, params object args);
private static string formathelper(iformatprovider provider, string format, paramsarray args)
if (format == null)
contract.ensures(contract.result() != null);
contract.endcontractblock();
int pos = 0;
int len = format.length;
char ch = '\x0';
icustomformatter cf = null;
if (provider != null)
while (true) ')
') // treat as escape character for }}
pos++;
else
formaterror();
}if (ch == '}}
if (pos == len) break;
pos++;
if (pos == len || (ch = format[pos]) < '0' || ch > '9') formaterror();
int index = 0;
do while (ch >= '0' && ch <= '9' && index < 1000000);
if (index >= args.length) throw new formatexception(environment.getresourcestring("format_indexoutofrange"));
while (pos < len && (ch = format[pos]) == ' ') pos++;
bool leftjustify = false;
int width = 0;
if (ch == ',')
if (ch < '0' || ch > '9') formaterror();
do while (ch >= '0' && ch <= '9' && width < 1000000);
}while (pos < len && (ch = format[pos]) == ' ') pos++;
object arg = args[index];
stringbuilder fmt = null;
if (ch == ':')
else if (ch == '}')
') // treat as escape character for }}
pos++;
else
}if (fmt == null) }}
if (ch != '}') formaterror();
pos++;
string sfmt = null;
string s = null;
if (cf != null)
s = cf.format(sfmt, arg, provider);
}if (s == null)
}#endif
if (formattablearg != null)
s = formattablearg.tostring(sfmt, provider);
} else if (arg != null)
}if (s == null) s = string.empty;
int pad = width - s.length;
}return this;
}
c# 6推出了字串內插語法,對比string.format()方法:
// source code
string name = "world";
console.writeline($"hello ");
int i = 10;
console.writeline($"i: ");
// il code
0000 nop
0001 ldstr "world"
0006 stloc.0
0007 ldstr "hello "
000c ldloc.0
000d call string [mscorlib]system.string::concat(string, string)
0012 call void [mscorlib]system.console::writeline(string)
0017 nop
0018 ldc.i4.s 10
001a stloc.1
001b ldstr "i: "
0020 ldloc.1
0021 box [mscorlib]system.int32
0026 call string [mscorlib]system.string::format(string, object)
002b call void [mscorlib]system.console::writeline(string)
0030 nop
0031 ret
從上文中的il**可以看到,呼叫c# 6版本的字串內插的時候,出現了裝箱操作,因此是有效能問題的。總結c# 6字串內插的一些效能、開銷、使用問題如下:
c# 10對字串內插進行了優化,如下.net 6**編譯後使用dnspy檢視反編譯後的c#**,可以看到其實現不再是呼叫string.format(),而是由defaultinterpolatedstringhandler處理字串內插。
// source code
int i = 10;
console.writeline($"i: ");
// 反編譯後
int i = 10;
defaultinterpolatedstringhandler defaultinterpolatedstringhandler = new defaultinterpolatedstringhandler(3, 1);
console.writeline(defaultinterpolatedstringhandler.tostringandclear());
namespace system.runtime.compilerservices
}
總結c# 10對字串內插進行優化後,有如下改進:
無需在執行時解析插值字串,編譯時進行了解析並生成了一系列的呼叫以便執行時構建字串;
提供ispanformattable介面,取代對object.tostring()或iformattable.tostring()的呼叫,無需生成臨時string。core libraries中的很多態別已實現該介面,提供更好的效能生成字串;
string提供了兩個靜態的create()方法過載,通過傳入iformatprovider及span進一步優化效能;
文中如有錯誤,歡迎交流指正。
字串格式化
sprintf snprintf snprintf std stringstream std strstream boost lexical cast boost format cstring format 1 sprintf 使用 sprintf 不安全,輕則破壞資料的準確性,重則程式崩潰。請看下...
格式化字串
通常在使用字串的時候,會對字串進行格式化,然後輸出或呼叫 一般我們使用替換標記對字串進行格式化 string str1 string.format add is 1,2,3 而且在c 中的替換標記可以以任意順序和次數出現在格式化字串中,但替換值是按順序排的,而且替換標記不能超出索引範圍 string...
字串格式化
例如 string s hello map.put target world string res format s,map 有什麼用呢?比如在some.properties中配置模板字串,但是如果用 這種方式,在配置了spring讀取properties注入變數的時候,這個變數就找不到會報錯。這個...