Sự khác nhau giữa String và StringBuilder?
An object is mutable if, once created, its state can be changed by calling various operations on it, otherwise it is immutable.
Immutable String
Mutable StringBuilder
String: là một kiểu dữ liệu reference type, không phải value type
Một chuỗi String có thể dài vô tận (nếu HEAP đủ lớn).
Đặc điểm của String là immutable, tức là String đã tạo ra thì không bao giờ thay đổi giá trị.
VD: String str1 = "ABC"; lệnh này tương đương với String str1 = new String("ABC");
-> sẽ tạo ra 1 String Object với gia trị là ABC, Object này sẽ không bao giờ thay đổi giá trị bằng bất cứ cách nào.
Đó là lý do tại sao tất cả các hàm của String như subString(), toLowerCase()... đều không thay đổi giá trị của nó, mà nó return 1 String mới.
Vậy chuyện gì sẽ xảy ra nếu chúng ta thêm đoạn code: String str1 = str1 + "D";
Đầu tiên chương trình sẽ tạo ra 1 String Object mới với giá trị là D, sau đó với toán tử +, một String mới nữa sẽ được tạo ra với giá trị là tổng của chúng (ABCD).
-> biến str1 sẽ trỏ đến String Object mới này. String Object với giá trị "ABC" ban đầu vẫn còn tồn tại ở đó.
StringBuilder, StringBuffer: Theo tính chất của String ở trên, vậy cứ khi nào bạn + 2 hay nhiều String, nó lại tạo ra rất nhiều Object mới, làm chậm chương trình
StringBuilder và StringBuffer sinh ra để giải quyết vấn đề này. Bạn sẽ chỉ tạo ra duy nhất 1 Object StirngBuilder hay StringBuffer, chương trình sẽ mặc định cấp phát 32 hay 64 bit cho nó.
Mỗi khi bạn thao tác trên Object này (append, remove...) thì giá trị của Object thay đổi mà không tạo ra Object khác.
Nếu vượt quá 32 hay 64 bit, nó sẽ tự động extend vùng cấp phát theo sỗ mũ của 2 (32=2^5, 64=2^6, 128=2^7...).
When to use System.String?
- Instances of immutable types are inherently thread-safe, since no thread can modify it, the risk of a thread modifying it in a way that interferes with another is removed (the reference itself is a different matter).
- Similarly, the fact that aliasing can't produce changes (if x and y both refer to the same object a change to x entails a change to y) allows for considerable compiler optimisations.
- Memory-saving optimisations are also possible. Interning and atomising being the most obvious examples, though we can do other versions of the same principle. I once produced a memory saving of about half a GB by comparing immutable objects and replacing references to duplicates so that they all pointed to the same instance (time-consuming, but a minute's extra start-up to save a massive amount of memory was a performance win in the case in question). With mutable objects that can't be done.
- No side-effects can come from passing an immutable type as a method to a parameter unless it is out or ref (since that changes the reference, not the object). A programmer therefore knows that if string x = "abc" at the start of a method, and that doesn't change in the body of the method, then x == "abc" at the end of the method.
- Conceptually, the semantics are more like value types; in particular equality is based on state rather than identity. This means that "abc" == "ab" + "c". While this doesn't require immutability, the fact that a reference to such a string will always equal "abc" throughout its lifetime (which does require immutability) makes uses as keys where maintaining equality to previous values is vital, much easier to ensure correctness of (strings are indeed commonly used as keys).
- Conceptually, it can make more sense to be immutable. If we add a month onto Christmas, we haven't changed Christmas, we have produced a new date in late January. It makes sense therefore that Christmas.AddMonths(1) produces a new DateTime rather than changing a mutable one. (Another example, if I as a mutable object change my name, what has changed is which name I am using, "Jon" remains immutable and other Jons will be unaffected.
- Copying is fast and simple, to create a clone just return this. Since the copy can't be changed anyway, pretending something is its own copy is safe.
- [Edit, I'd forgotten this one]. Internal state can be safely shared between objects. For example, if you were implementing list which was backed by an array, a start index and a count, then the most expensive part of creating a sub-range would be copying the objects. However, if it was immutable then the sub-range object could reference the same array, with only the start index and count having to change, with a very considerable change to construction time.
In all, for objects which don't have undergoing change as part of their purpose, there can be many advantages in being immutable. The main disadvantage is in requiring extra constructions, though even here it's often overstated (remember, you have to do several appends before StringBuilder becomes more efficient than the equivalent series of concatenations, with their inherent construction).
It would be a disadvantage if mutability was part of the purpose of an object (who'd want to be modeled by an Employee object whose salary could never ever change) though sometimes even then it can be useful (in a many web and other stateless applications, code doing read operations is separate from that doing updates, and using different objects may be natural - I wouldn't make an object immutable and then force that pattern, but if I already had that pattern I might make my "read" objects immutable for the performance and correctness-guarantee gain).
Copy-on-write is a middle ground. Here the "real" class holds a reference to a "state" class. State classes are shared on copy operations, but if you change the state, a new copy of the state class is created. This is more often used with C++ than C#, which is why it's std:string enjoys some, but not all, of the advantages of immutable types, while remaining mutable.
When to use System.Text.StringBuilder?
- Definitely use StringBuilder when you're concatenating in a non-trivial loop - especially if you don't know for sure (at compile time) how many iterations you'll make through the loop. For example, reading a file a character at a time, building up a string as you go using the += operator is potentially performance suicide.
- Definitely use the concatenation operator when you can (readably) specify everything which needs to be concatenated in one statement. (If you have an array of things to concatenate, consider calling String.Concat explicitly - or String.Join if you need a delimiter.)
- Don't be afraid to break literals up into several concatenated bits - the result will be the same. You can aid readability by breaking a long literal into several lines, for instance, with no harm to performance.
- If you need the intermediate results of the concatenation for something other than feeding the next iteration of concatenation, StringBuilder isn't going to help you. For instance, if you build up a full name from a first name and a last name, and then add a third piece of information (the nickname, maybe) to the end, you'll only benefit from using StringBuilder if you don't need the (first name + last name) string for other purpose (as we do in the example which creates a Person object).
- If you just have a few concatenations to do, and you really want to do them in separate statements, it doesn't really matter which way you go. Which way is more efficient will depend on the number of concatenations the sizes of string involved, and what order they're concatenated in. If you really believe that piece of code to be a performance bottleneck, profile or benchmark it both ways.
Chương trình kiểm tra kiến thức về String và StringBuilder
Tôi biết rằng string là immutable và StringBuilder là mutable. Nhưng bất cứ ai có thể giải thích sau code ra? Kể từ khi cả hai đều là các loại tham chiếu, tại sao họ có kết quả khác nhau?
String s1 = "hello";
String s2 = "hello";
Console.WriteLine(s1 == s2); //true
Console.WriteLine(Object.ReferenceEquals(s1, s2)); //true
Giải thích tại sao kết quả ở trên lại trả về true https://abhijit-k-adhikari.me/category/c/
StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = new StringBuilder("hello");
Console.WriteLine(sb1 == sb2); //false
Console.WriteLine(Object.ReferenceEquals(sb1, sb2)); //false
Giải thích tại sao kết quả ở trên lại trả về false https://abhijit-k-adhikari.me/category/c/
So sánh Java và C# tổng quan?
https://www.harding.edu/fmccown/java_csharp_comparison.html
Phân biệt Class và Structure trong C#
Lớp và Cấu trúc trong C# có một số điểm khác nhau cơ bản sau:
-
Các class là các kiểu tham chiếu, còn struct là các kiểu giá trị.
-
Struct không hỗ trợ tính kế thừa.
-
Struct không có constructor mặc định.
- Struct không có các khai báo biến abstract, virtual, protected
Từ khóa dynamic là gì?
Kiểu dynamic tương tự với kiểu object, ngoại trừ việc kiểm tra cho các biến kiểu object diễn ra tại compile time, trong khi việc kiểm tra các biến kiểu dynamic diễn ra tại run time.
Kiểu dữ liệu
object: kiểu dữ liệu tham chiếu, kiểu dữ liệu cơ bản của tất cả các kiểu khác
string: kiểu dữ liệu tham chiếu, được sử dụng để lưu trữ những giá trị kiểu chữ cho biến
struct: kiểu dữ liệu tham chiếu
int: sử dụng để lưu trữ giá trị kiểu số nguyên
byte: sử dụng để lưu trữ giá byte
float: sử dụng để lưu trữ giá trị số thực
bool: sử dụng để lưu trữ giá trị đúng hoặc sai
char: sử dụng để lưu trữ một ký tự
C# version:
-
C# 1.0 with Visual Studio.NET
-
C# 2.0 with Visual Studio 2005
-
C# 3.0 with Visual Studio 2008
-
C# 4.0 with Visual Studio 2010
-
C# 5.0 with Visual Studio 2012
-
C# 6.0 with Visual Studio 2015
-
C# 7.0 with Visual Studio 2017
These are the versions of C# known about at the time of this writing:
- C# 1.0 released with .NET 1.0 and VS2002 (January 2002)
- C# 1.2 (bizarrely enough); released with .NET 1.1 and VS2003 (April 2003). First version to call Dispose on IEnumerators which implemented IDisposable. A few other small features.
- C# 2.0 released with .NET 2.0 and VS2005 (November 2005). Major new features: generics, anonymous methods, nullable types, iterator blocks
- C# 3.0 released with .NET 3.5 and VS2008 (November 2007). Major new features: lambda expressions, extension methods, expression trees, anonymous types, implicit typing (var), query expressions
- C# 4.0 released with .NET 4 and VS2010 (April 2010). Major new features: late binding (dynamic), delegate and interface generic variance, more COM support, named arguments, tuple data type and optional parameters
- C# 5.0 released with .NET 4.5 and VS2012 (August 2012). Major features: async programming, caller info attributes. Breaking change: loop variable closure.
- C# 6.0 released with .NET 4.6 and VS2015 (July 2015). Implemented by Roslyn. Features: initializers for automatically implemented properties, using directives to import static members, exception filters, indexed members and element initializers, await in catch and finally, extension Add methods in collection initializers.
- C# 7.0 released with .NET 4.7 and VS2017 (March 2017) Major new features: tuples, ref locals and ref return, pattern matching (including pattern-based switch statements), inline outparameter declarations, local functions, binary literals, digit separators, and arbitrary async returns.
- C# 7.1 released with .NET 4.7 and VS2017 v15.3 (August 2017) Minor new features: async main, tuple member name inference, default expression, pattern matching with generics.
There is no such thing as C# 3.5 - the cause of confusion here is that the C# 3.0 is present in .NET 3.5. The language and framework are versioned independently, however - as is the CLR, which is at version 2.0 for .NET 2.0 through 3.5, .NET 4 introducing CLR 4.0, service packs notwithstanding. The CLR in .NET 4.5 has various improvements, but the versioning is unclear: in some places it may be referred to as CLR 4.5 (this MSDN page used to refer to it that way, for example), but the Environment.Version property still reports 4.0.xxx.
More detailed information about the relationship between the language, runtime and framework versions is available on the C# in Depth site. This includes information about which features of C# 3.0 you can use when targeting .NET 2.0. (If anyone wants to bring all of the content into this wiki answer, they're welcome to.)
As of May 3, 2017, the C# Language Team created a history of C# versions and features on their github repo: Features Added in C# Language Versions
Features Added in C# Language Versions
C# 1.0 (Visual Studio.NET)
- Classes
- Structs
- Interfaces
- Events
- Properties
- Delegates
- Expressions
- Statements
- Attributes
- Literals
C# 2 (VS 2005)
- Generics
- Partial types
- Anonymous methods
- Iterators
- Nullable types
- Getter/setter separate accessibility
- Method group conversions (delegates)
- Co- and Contra-variance for delegates and interfaces
- Static classes
- Delegate inference
C# 3 (VS 2008)
- Implicitly typed local variables
- Object and collection initializers
- Auto-Implemented properties
- Anonymous types
- Extension methods
- Query expressions
- Lambda expression
- Expression trees
- Partial methods
C# 4 (VS 2010)
- Dynamic binding
- Named and optional arguments
- Generic co- and contravariance
- Embedded interop types ("NoPIA")
C# 5 (VS 2012)
- Asynchronous methods
- Caller info attributes
C# 6 (VS 2015)
- Draft Specification online
- Compiler-as-a-service (Roslyn)
- Import of static type members into namespace
- Exception filters
- Await in catch/finally blocks
- Auto property initializers
- Default values for getter-only properties
- Expression-bodied members
- Null propagator (null-conditional operator, succinct null checking)
- String interpolation
- nameof operator
- Dictionary initializer
C# 7.0 (Visual Studio 2017)
C# 7.1 (Visual Studio 2017 version 15.3)