string in .net
TRANSCRIPT
STRING IN .NETLarry Nung
AGENDA
String
String operations
“”& String.Empty
Null & Empty check
String pool
String property
StringBuilder
Reference
Q & A
2
STRING
3
STRING
[SerializableAttribute] [ComVisibleAttribute(true)]
public sealed class String : IComparable,
ICloneable, IConvertible, IComparable<string>,
IEnumerable<char>, IEnumerable,
IEquatable<string>
4
STRING
[SerializableAttribute] [ComVisibleAttribute(true)]
public sealed class String : IComparable,
ICloneable, IConvertible, IComparable<string>,
IEnumerable<char>, IEnumerable,
IEquatable<string>
5
STRING
6
STRING
7
STRING OPERATIONS
8
STRING OPERATIONS
var name = "LevelUp";
var url = "http://larrynung.github.io/";
var str1 = name + " (" + url + ")";
var str2 = string.Concat(name, " (", url, ")");
var str3 = string.Format("{0} ({1})", name, url);
var str4 = @"Blog: LevelUp Url: http://larrynung.github.io/";
var str5 = "c:\\Blog\\LevelUp";
var str6 = @"c:\Blog\LevelUp";
var msg = string.Empty;
msg += String.Format("str1 == str2 => {0}", str1 == str2);
msg += Environment.NewLine;
msg += String.Format("str1.Equals(str3) => {0}", str1.Equals(str3));
msg += Environment.NewLine;
msg += str4;
msg += Environment.NewLine;
msg += str5;
msg += Environment.NewLine;
msg += str6;
msg += Environment.NewLine; Console.WriteLine(msg);9
“”& STRING.EMPTY
10
“” & STRING.EMPTY
11
“” & STRING.EMPTY
static void Main(string[] args) {
int count = 1000000000;
EmptyString1(count); EmptyString2(count); EmptyString3(count);
}
private static void EmptyString1(int count) {
String test; Stopwatch sw = Stopwatch.StartNew();
for (int idx = 0; idx < count; ++idx) { test = ""; }
sw.Stop();
Console.WriteLine("EmptyString1: " + sw.ElapsedMilliseconds.ToString());
}
private static void EmptyString2(int count) {
String test; Stopwatch sw = Stopwatch.StartNew();
for (int idx = 0; idx < count; ++idx) { test = string.Empty; }
sw.Stop();
Console.WriteLine("EmptyString2: " + sw.ElapsedMilliseconds.ToString());
}
private static void EmptyString3(int count) {
String test; Stopwatch sw = Stopwatch.StartNew();
for (int idx = 0; idx < count; ++idx) { test = new String(' ',0); }
sw.Stop();
Console.WriteLine("EmptyString3: " + sw.ElapsedMilliseconds.ToString());
}
12
“” & STRING.EMPTY
static void Main(string[] args) {
int count = 1000000000;
EmptyString1(count); EmptyString2(count); EmptyString3(count);
}
private static void EmptyString1(int count) {
String test; Stopwatch sw = Stopwatch.StartNew();
for (int idx = 0; idx < count; ++idx) { test = ""; }
sw.Stop();
Console.WriteLine("EmptyString1: " + sw.ElapsedMilliseconds.ToString());
}
private static void EmptyString2(int count) {
String test; Stopwatch sw = Stopwatch.StartNew();
for (int idx = 0; idx < count; ++idx) { test = string.Empty; }
sw.Stop();
Console.WriteLine("EmptyString2: " + sw.ElapsedMilliseconds.ToString());
}
private static void EmptyString3(int count) {
String test; Stopwatch sw = Stopwatch.StartNew();
for (int idx = 0; idx < count; ++idx) { test = new String(' ',0); }
sw.Stop();
Console.WriteLine("EmptyString3: " + sw.ElapsedMilliseconds.ToString());
}
130
1000
2000
3000
4000
5000
6000
7000
1000000 10000000 1000000000
""
String.Empty
new String()
“” & STRING.EMPTY
static void Main(string[] args) {
int count = 1000000000;
EmptyString1(count); EmptyString2(count); EmptyString3(count);
}
private static void EmptyString1(int count) {
String test; Stopwatch sw = Stopwatch.StartNew();
for (int idx = 0; idx < count; ++idx) { test = ""; }
sw.Stop();
Console.WriteLine("EmptyString1: " + sw.ElapsedMilliseconds.ToString());
}
private static void EmptyString2(int count) {
String test; Stopwatch sw = Stopwatch.StartNew();
for (int idx = 0; idx < count; ++idx) { test = string.Empty; }
sw.Stop();
Console.WriteLine("EmptyString2: " + sw.ElapsedMilliseconds.ToString());
}
private static void EmptyString3(int count) {
String test; Stopwatch sw = Stopwatch.StartNew();
for (int idx = 0; idx < count; ++idx) { test = new String(' ',0); }
sw.Stop();
Console.WriteLine("EmptyString3: " + sw.ElapsedMilliseconds.ToString());
}
140
1000
2000
3000
4000
5000
6000
7000
1000000 10000000 1000000000
""
String.Empty
new String()
NULL & EMPTY CHECK
15
NULL & EMPTY CHECK
Check with == null
e.x. if (str == nill)
Check with == ""
e.x. if (str == “”)
Check with == String.Empty
e.x. if (str == String.Empty)
Check with String.IsNullOrEmpty(str)
e.x. if (String.IsNullOrEmpty(str))
Check with String.Length == 0
e.x. if (str.Length == 0)
16
NULL & EMPTY CHECK
private static void Main(string[] args) {
string[] testStrings = new string[] { null, "", string.Empty };
foreach (string str in testStrings) {
TestString(str);
Console.WriteLine("=======================");
}
}
private static void TestString(string str) {
if (str == null)
Console.WriteLine("str = null");
if (str == "")
Console.WriteLine("str = \"\"");
if (str == string.Empty)
Console.WriteLine("str = String.Empty");
if (string.IsNullOrEmpty(str))
Console.WriteLine("String.IsNullOrEmpty(str)");
try {
if (str.Length == 0) Console.WriteLine("str.Length = 0");
} catch (Exception ex) { }
}17
NULL & EMPTY CHECK
private static void Main(string[] args) {
string[] testStrings = new string[] { null, "", string.Empty };
foreach (string str in testStrings) {
TestString(str);
Console.WriteLine("=======================");
}
}
private static void TestString(string str) {
var count = 100000000;
Console.WriteLine("str == null: {0} ms",
DoTest(count, () => { var result = str == null; }));
Console.WriteLine("str == \"\": {0} ms",
DoTest(count, () => { var result = str == ""; }));
Console.WriteLine("str == String.Empty: {0} ms",
DoTest(count, () => { var result = str == String.Empty; }));
Console.WriteLine("string.IsNullOrEmpty(str): {0} ms",
DoTest(count, () => { var result = string.IsNullOrEmpty(str); }));
try {
Console.WriteLine("str.Length == 0: {0} ms",
DoTest(count, () => { var result = str.Length == 0; }));
} catch { }
}
static long DoTest(int count, Action action)
{
var sw = Stopwatch.StartNew();
for (int i = 0; i < count; ++i) action();
return sw.ElapsedMilliseconds;
}
18
NULL & EMPTY CHECK
private static void Main(string[] args) {
string[] testStrings = new string[] { null, "", string.Empty };
foreach (string str in testStrings) {
TestString(str);
Console.WriteLine("=======================");
}
}
private static void TestString(string str) {
var count = 100000000;
Console.WriteLine("str == null: {0} ms",
DoTest(count, () => { var result = str == null; }));
Console.WriteLine("str == \"\": {0} ms",
DoTest(count, () => { var result = str == ""; }));
Console.WriteLine("str == String.Empty: {0} ms",
DoTest(count, () => { var result = str == String.Empty; }));
Console.WriteLine("string.IsNullOrEmpty(str): {0} ms",
DoTest(count, () => { var result = string.IsNullOrEmpty(str); }));
try {
Console.WriteLine("str.Length == 0: {0} ms",
DoTest(count, () => { var result = str.Length == 0; }));
} catch { }
}
static long DoTest(int count, Action action)
{
var sw = Stopwatch.StartNew();
for (int i = 0; i < count; ++i) action();
return sw.ElapsedMilliseconds;
}
19
STRING POOL
20
STRING POOL
var str1 = "aaaa";
var str2 = "aa" + "aa";
var str3 = "aa"; str3 += str3;
var str4 = new string('a', 4);
var str5 = string.Intern(str4);
Debug.WriteLine(ReferenceEquals(str1, str2));
Debug.WriteLine(ReferenceEquals(str1, str3));
Debug.WriteLine(ReferenceEquals(str1, str4));
Debug.WriteLine(ReferenceEquals(str1, str5));
21
STRING POOL
var str1 = "aaaa";
var str2 = "aa" + "aa";
var str3 = "aa"; str3 += str3;
var str4 = new string('a', 4);
var str5 = string.Intern(str4);
Debug.WriteLine(ReferenceEquals(str1, str2));
Debug.WriteLine(ReferenceEquals(str1, str3));
Debug.WriteLine(ReferenceEquals(str1, str4));
Debug.WriteLine(ReferenceEquals(str1, str5));
22
STRING POOL
var str1 = "aaaa";
var str2 = "aa" + "aa";
var str3 = "aa"; str3 += str3;
var str4 = new string('a', 4);
var str5 = string.Intern(str4);
Debug.WriteLine(ReferenceEquals(str1, str2));
Debug.WriteLine(ReferenceEquals(str1, str3));
Debug.WriteLine(ReferenceEquals(str1, str4));
Debug.WriteLine(ReferenceEquals(str1, str5));
23
str1
str2
str3
str4
“aaaa”
“aaaa”
str5 “aaaa”
String Pool
STRING PROPERTY
24
STRING PROPERTY
internal class Program
{
public String Name { get; set; }
}
25
STRING PROPERTY
internal class Program
{
public String Name { get; set; }
}
26
STRING PROPERTY
internal class Program
{
public String Name { get; set; }
}
27
STRING PROPERTY
internal class Program
{
private String _name;
public String Name
{
get { return _name ?? String.Empty; }
set { _name = value; }
}
}
28
STRINGBUILDER
29
STRINGBUILDER
Consider using the String class under these conditions:
When the number of changes that your app will make to a string is small. In these cases, StringBuilder might offer negligible or no performance improvement over String.
When you are performing a fixed number of concatenation operations, particularly with string literals. In this case, the compiler might combine the concatenation operations into a single operation.
When you have to perform extensive search operations while you are building your string. The StringBuilder class lacks search methods such as IndexOf or StartsWith. You'll have to convert the StringBuilderobject to a String for these operations, and this can negate the performance benefit from using StringBuilder. For more information, see the Searching the text in a StringBuilder object section.
30
STRINGBUILDER
Consider using the StringBuilder class under these
conditions:
When you expect your app to make an unknown
number of changes to a string at design time (for
example, when you are using a loop to concatenate a
random number of strings that contain user input).
When you expect your app to make a significant
number of changes to a string.
31
STRINGBUILDER
var count = 1000000;
var result = string.Empty;
var sw = Stopwatch.StartNew();
for (var index = 0; index < count; ++index)
result += "a";
Console.WriteLine(sw.ElapsedMilliseconds);
result = string.Empty;
sw.Restart();
var sb = new StringBuilder();
for (var index = 0; index < count; ++index)
sb.Append("a");
result = sb.ToString();
Console.WriteLine(sw.ElapsedMilliseconds);
32
0
50000
100000
150000
200000
250000
300000
350000
1000 10000 100000 1000000
String concat
StringBuilder
“aaaa”
164
“aaaaaaaaaaaaaaaa”
16
“aaaaaaaaaaaaaaaaa”
3217
“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa”
6433
REFERENCE
33
REFERENCE
[.Net Concept]理解並善用String pool - Level Up-點部落
http://www.dotblogs.com.tw/larrynung/archive/2011/06/3
0/30763.aspx
[Performance][C#]String.Empty V.S “” - Level Up-
點部落
http://www.dotblogs.com.tw/larrynung/archive/2009/12/2
2/12615.aspx
[Performance][VB.NET].NET空字串判斷徹底研究 -
Level Up-點部落
http://www.dotblogs.com.tw/larrynung/archive/2009/03/1
3/7461.aspx 34
REFERENCE
[.NET Concept]集合與字串類型的屬性和方法應避免回傳null - Level Up-點部落
http://www.dotblogs.com.tw/larrynung/archive/2011/04/1
6/22866.aspx
String與Stringbuilder組字串的效能比較 - Jeff 隨手記-點部落
http://www.dotblogs.com.tw/jeff-
yeh/archive/2008/11/04/5870.aspx
[C#.NET] 動態處理字串 - StringBuilder類別與String 類別的效能 -余小章@ 大內殿堂-點部落
http://www.dotblogs.com.tw/yc421206/archive/2010/10/
26/18575.aspx 35
REFERENCE
StringBuilder串接字串的迷思 -黑暗執行緒
http://blog.darkthread.net/blogs/darkthreadtw/archive/20
07/12/15/stringbuilder-for-static-string-concate.aspx
Heikniemi Hardcoded » .net String vs.
StringBuilder – concatenation performance
http://www.heikniemi.net/hardcoded/2004/08/net-string-
vs-stringbuilder-concatenation-performance/
StringBuilder Class (System.Text)
https://msdn.microsoft.com/en-
us//library/system.text.stringbuilder.aspx
36
REFERENCE
文章-StringBuilder與String的字串相接效能大車拼 -
黑暗執行緒
http://blog.darkthread.net/blogs/darkthreadtw/archive/20
09/09/07/article-stringbuilder-vs-string.aspx
Performance considerations for strings in C# -
CodeProject
http://www.codeproject.com/Articles/10318/Performance
-considerations-for-strings-in-C
Improving String Handling Performance in .NET
Framework Applications
https://msdn.microsoft.com/en-
us/library/aa302329.aspx?f=255&MSPPError=-
214721739637
REFERENCE
Introduction to Programming with C# / Java Books
» Chapter 13. Strings and Text Processing
http://www.introprogramming.info/english-intro-csharp-
book/read-online/chapter-13-strings-and-text-
processing/
38
Q&A39
QUESTION & ANSWER
40