格式化字串

2022-09-19 21:36:29 字數 4696 閱讀 9937

按照格式化字串功能的進化,本文討論下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注入變數的時候,這個變數就找不到會報錯。這個...