Câu trả lời:
Trong .NET trước phiên bản 2.0, ""
tạo một đối tượng trong khi string.Empty
không tạo đối tượng ref , điều này làm cho string.Empty
hiệu quả hơn.
Trong phiên bản 2.0 trở lên của .NET, tất cả các lần xuất hiện ""
đều đề cập đến cùng một chuỗi ký tự, có nghĩa ""
là tương đương .Empty
, nhưng vẫn không nhanh như .Length == 0
.
.Length == 0
là tùy chọn nhanh nhất, nhưng .Empty
làm cho mã sạch hơn một chút.
string.IsNullOrEmpty( stringVar )
.
sự khác biệt giữa String.Empty và "" là gì và chúng có thể hoán đổi cho nhau không
string.Empty
là trường chỉ đọc trong khi đó ""
là hằng số thời gian biên dịch. Những nơi họ cư xử khác nhau là:
Giá trị tham số mặc định trong C # 4.0 trở lên
void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
//... implementation
}
Biểu hiện trường hợp trong câu lệnh switch
string str = "";
switch(str)
{
case string.Empty: // Error: A constant value is expected.
break;
case "":
break;
}
Đối số thuộc tính
[Example(String.Empty)]
// Error: An attribute argument must be a constant expression, typeof expression
// or array creation expression of an attribute parameter type
String.Empty
như một đối số trong hầu hết các trường hợp. Bạn đúng rằng tất cả các ví dụ cho thấy điều đó you simply can't put a (run-time) "value" into (compile-time) metadata
và đó là những gì các ví dụ đang nhắm đến để hiển thị.
Các câu trả lời trước đó là chính xác cho .NET 1.1 (xem ngày của bài đăng mà họ liên kết: 2003). Kể từ .NET 2.0 trở lên, về cơ bản không có sự khác biệt. JIT cuối cùng sẽ tham chiếu cùng một đối tượng trên heap.
Theo thông số kỹ thuật của C #, phần 2.4.4.5: http://msdn.microsoft.com/en-us/l Library / aa691090 (VS.71) .aspx
Mỗi chuỗi ký tự không nhất thiết dẫn đến một thể hiện chuỗi mới. Khi hai hoặc nhiều chuỗi ký tự chuỗi tương đương theo toán tử đẳng thức chuỗi (Mục 7.9.7) xuất hiện trong cùng một cụm, các chuỗi ký tự chuỗi này tham chiếu đến cùng một thể hiện chuỗi.
Thậm chí có người còn đề cập đến điều này trong các bình luận trong bài đăng của Brad Abram
Tóm lại, kết quả thực tế của "" so với String.Empty là không. JIT sẽ tìm ra nó cuối cùng.
Cá nhân tôi đã phát hiện ra rằng JIT thông minh hơn tôi rất nhiều và vì vậy tôi cố gắng không quá thông minh với các tối ưu hóa trình biên dịch vi mô như thế. JIT sẽ mở ra các vòng lặp (), loại bỏ mã dự phòng, phương thức nội tuyến, v.v. tốt hơn và vào thời điểm thích hợp hơn so với trình biên dịch I hoặc C # có thể dự đoán trước. Hãy để JIT thực hiện công việc của mình :)
String.Empty
là một trường chỉ đọc trong khi ""
là một const . Điều này có nghĩa là bạn không thể sử dụng String.Empty
trong câu lệnh chuyển đổi vì nó không phải là hằng số.
default
từ khóa, chúng ta có thể thúc đẩy khả năng đọc mà không cần, ngăn chặn sửa đổi ngẫu nhiên và có hằng số thời gian biên dịch, mặc dù thành thật mà nói, tôi vẫn nghĩ String.Empty dễ đọc hơn mặc định, nhưng gõ chậm hơn
Một điểm khác biệt nữa là String.Empty tạo mã CIL lớn hơn. Mặc dù mã để tham chiếu "" và String.Empty có cùng độ dài, trình biên dịch không tối ưu hóa nối chuỗi (xem bài đăng trên blog của Eric Lippert ) cho các đối số String.Empty. Các chức năng tương đương sau
string foo()
{
return "foo" + "";
}
string bar()
{
return "bar" + string.Empty;
}
tạo IL này
.method private hidebysig instance string foo() cil managed
{
.maxstack 8
L_0000: ldstr "foo"
L_0005: ret
}
.method private hidebysig instance string bar() cil managed
{
.maxstack 8
L_0000: ldstr "bar"
L_0005: ldsfld string [mscorlib]System.String::Empty
L_000a: call string [mscorlib]System.String::Concat(string, string)
L_000f: ret
}
"bar " + (ok ? "" : "error")
Các câu trả lời trên là đúng về mặt kỹ thuật, nhưng những gì bạn có thể thực sự muốn sử dụng, để dễ đọc mã nhất và ít có khả năng có ngoại lệ nhất là String.IsNullOrEmpty (s)
--foo=$BAR
thì có lẽ bạn muốn phát hiện ra sự khác biệt giữa chúng mà quên đặt một var env và chúng không chuyển cờ. string.IsNullOrEmpty
thường là một mùi mã mà bạn chưa xác thực đầu vào của mình đúng cách hoặc đang làm những điều kỳ lạ. Nói chung, bạn không nên chấp nhận các chuỗi trống khi bạn thực sự muốn sử dụng null
hoặc một cái gì đó như loại Có thể / Tùy chọn.
Tôi có xu hướng sử dụng String.Empty
thay ""
vì một lý do đơn giản, nhưng không rõ ràng:
""
và ""
KHÔNG giống nhau, cái đầu tiên thực sự có 16 ký tự có chiều rộng bằng không. Rõ ràng không có nhà phát triển có thẩm quyền nào sẽ đưa các ký tự có độ rộng bằng không vào mã của họ, nhưng nếu họ vào đó, đó có thể là một cơn ác mộng bảo trì.
Ghi chú:
Tôi đã sử dụng U + FEFF trong ví dụ này.
Không chắc SO có ăn những ký tự đó không, nhưng hãy tự mình thử với một trong nhiều ký tự có độ rộng bằng không
Tôi chỉ đến nhờ điều này nhờ https://codegolf.stackexchange.com/
Sử dụng String.Empty
chứ không phải ""
.
Đây là nhiều hơn cho tốc độ hơn sử dụng bộ nhớ nhưng nó là một mẹo hữu ích. Đây
""
là một nghĩa đen vì vậy sẽ hoạt động như một nghĩa đen: trong lần sử dụng đầu tiên, nó được tạo ra và cho các lần sử dụng sau, tham chiếu của nó được trả về. Chỉ có một phiên bản""
sẽ được lưu trữ trong bộ nhớ cho dù chúng tôi sử dụng bao nhiêu lần! Tôi không thấy bất kỳ hình phạt bộ nhớ ở đây. Vấn đề là mỗi lần""
sử dụng, một vòng lặp so sánh được thực thi để kiểm tra xem cái đó""
đã có trong nhóm thực tập chưa. Mặt khác,String.Empty
là một tham chiếu đến vùng""
được lưu trữ trong vùng bộ nhớ .NET Framework .String.Empty
đang trỏ đến cùng một địa chỉ bộ nhớ cho các ứng dụng VB.NET và C #. Vậy tại sao tìm kiếm một tài liệu tham khảo mỗi khi bạn cần""
khi bạn có tài liệu tham khảo đó trongString.Empty
?
Tham khảo: String.Empty
vs""
String.Empty không tạo đối tượng trong khi "" không. Sự khác biệt, như được chỉ ra ở đây , là tầm thường, tuy nhiên.
Tất cả các trường hợp của "" là giống nhau, chuỗi ký tự được thực hiện (hoặc chúng phải như vậy). Vì vậy, bạn thực sự sẽ không ném một đối tượng mới vào đống mỗi khi bạn sử dụng "" mà chỉ tạo một tham chiếu đến cùng một đối tượng được thực hiện. Có nói rằng, tôi thích chuỗi.Empty. Tôi nghĩ rằng nó làm cho mã dễ đọc hơn.
Nó không thành vấn đề!
Một số thảo luận trước đây về điều này:
http: //www.codinghorror.com/blog/archives/000185.html
string mystring = "";
ldstr ""
ldstr
đẩy một tham chiếu đối tượng mới đến một chuỗi ký tự được lưu trữ trong siêu dữ liệu.
string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty
ldsfld
đẩy giá trị của trường tĩnh lên ngăn xếp đánh giá
Tôi có xu hướng sử dụng String.Empty
thay ""
vì bởi vì IMHO rõ ràng hơn và ít VB-ish hơn.
Eric Lippert đã viết (ngày 17 tháng 6 năm 2013):
"Thuật toán đầu tiên tôi từng làm trong trình biên dịch C # là trình tối ưu hóa xử lý các chuỗi nối. Thật không may, tôi đã không quản lý được các tối ưu hóa này cho cơ sở mã Roslyn trước khi tôi rời đi; đến đó! "
Dưới đây là một số kết quả Roslyn x64 vào tháng 1 năm 2019. Mặc dù có những nhận xét đồng thuận về các câu trả lời khác trên trang này, nhưng đối với tôi, JIT x64 hiện tại đang xử lý tất cả các trường hợp này một cách chính xác, khi tất cả được nói và thực hiện.
Tuy nhiên, đặc biệt lưu ý rằng chỉ có một trong những ví dụ này thực sự kết thúc cuộc gọi String.Concat
và tôi đoán đó là lý do chính xác tối nghĩa (trái ngược với giám sát tối ưu hóa). Những khác biệt khác có vẻ khó giải thích hơn.
mặc định (Chuỗi) + {mặc định (Chuỗi), "", String.Empty}
static String s00() => default(String) + default(String);
mov rax,[String::Empty]
mov rax,qword ptr [rax]
add rsp,28h
ret
static String s01() => default(String) + "";
mov rax,[String::Empty]
mov rax,qword ptr [rax]
add rsp,28h
ret
static String s02() => default(String) + String.Empty;
mov rax,[String::Empty]
mov rax,qword ptr [rax]
mov rdx,rax
test rdx,rdx
jne _L
mov rdx,rax
_L: mov rax,rdx
add rsp,28h
ret
"" + {mặc định (Chuỗi), "", Chuỗi.Empty}
static String s03() => "" + default(String);
mov rax,[String::Empty]
mov rax,qword ptr [rax]
add rsp,28h
ret
static String s04() => "" + "";
mov rax,[String::Empty]
mov rax,qword ptr [rax]
add rsp,28h
ret
static String s05() => "" + String.Empty;
mov rax,[String::Empty]
mov rax,qword ptr [rax]
mov rdx,rax
test rdx,rdx
jne _L
mov rdx,rax
_L: mov rax,rdx
add rsp,28h
ret
Chuỗi.Empty + {mặc định (Chuỗi), "", String.Empty}
static String s06() => String.Empty + default(String);
mov rax,[String::Empty]
mov rax,qword ptr [rax]
mov rdx,rax
test rdx,rdx
jne _L
mov rdx,rax
_L: mov rax,rdx
add rsp,28h
ret
static String s07() => String.Empty + "";
mov rax,[String::Empty]
mov rax,qword ptr [rax]
mov rdx,rax
test rdx,rdx
jne _L
mov rdx,rax
_L: mov rax,rdx
add rsp,28h
ret
static String s08() => String.Empty + String.Empty;
mov rcx,[String::Empty]
mov rcx,qword ptr [rcx]
mov qword ptr [rsp+20h],rcx
mov rcx,qword ptr [rsp+20h]
mov rdx,qword ptr [rsp+20h]
call F330CF60 ; <-- String.Concat
nop
add rsp,28h
ret
Microsoft (R) Visual C# Compiler version 2.10.0.0 (b9fb1610)
AMD64 Release
[MethodImpl(MethodImplOptions.NoInlining)]
'SuppressJitOptimization' = false
Xuất phát từ quan điểm Khung thực thể: Các phiên bản EF 6.1.3 xuất hiện để xử lý String.Empty và "" khác nhau khi xác thực.
chuỗi.Empty được coi là giá trị null cho mục đích xác thực và sẽ đưa ra lỗi xác thực nếu nó được sử dụng trên trường Bắt buộc (được quy); trong đó "" sẽ vượt qua xác nhận và không ném lỗi.
Vấn đề này có thể được giải quyết trong EF 7+. Tham khảo: - https://github.com/aspnet/EntityFramework/issues/2610 ).
Chỉnh sửa: [Bắt buộc (AllowEmptyStrings = true)] sẽ giải quyết vấn đề này, cho phép chuỗi.Empty xác thực.
Vì String.Empty không phải là hằng số thời gian biên dịch, bạn không thể sử dụng nó làm giá trị mặc định trong định nghĩa hàm.
public void test(int i=0,string s="")
{
// Function Body
}
public void test(int i=0, string s=string.Empty) {}
sẽ không biên dịch và nói "Giá trị tham số mặc định cho 's' phải là hằng số thời gian biên dịch. Câu trả lời của OP hoạt động.
Khi bạn đang quét trực quan thông qua mã, "" sẽ xuất hiện màu theo cách các chuỗi được tô màu. chuỗi.Empty trông giống như một truy cập thành viên lớp thông thường. Trong một cái nhìn nhanh, dễ dàng phát hiện ra "" hoặc trực giác nghĩa.
Phát hiện các chuỗi (màu sắc ngăn xếp chồng lên nhau không chính xác, nhưng trong VS thì điều này rõ ràng hơn):
var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;
\u00ad
.
Mọi người ở đây đã đưa ra một số làm rõ lý thuyết tốt. Tôi đã có một nghi ngờ tương tự. Vì vậy, tôi đã thử một mã hóa cơ bản trên nó. Và tôi đã tìm thấy một sự khác biệt. Đây là sự khác biệt.
string str=null;
Console.WriteLine(str.Length); // Exception(NullRefernceException) for pointing to null reference.
string str = string.Empty;
Console.WriteLine(str.Length); // 0
Vì vậy, có vẻ như "Null" có nghĩa là hoàn toàn void & "String.Empty" có nghĩa là Nó chứa một số loại giá trị, nhưng nó trống rỗng.
""
so với string.Empty
. Chỉ khi cố gắng để biết nếu chuỗi là trống, null
đã được đề cập.
string.Empty
và lý do đằng sau tuyên bố nó là gìreadonly
thay vìconst
.