سؤال

في .NET، ما هو الفرق بين String.Empty و "", ، وهل هي قابلة للتبديل، أم أن هناك بعض المشكلات المرجعية أو التوطين الأساسية حول المساواة؟ String.Empty سوف تضمن ليست مشكلة؟

هل كانت مفيدة؟

المحلول

في .NET قبل الإصدار 2.0، "" يخلق كائن بينما string.Empty لا يخلق أي كائنالمرجع, ، مما يجعل string.Empty أكثر فعالية.

في الإصدار 2.0 والإصدارات الأحدث من .NET، كافة تكرارات "" الرجوع إلى نفس السلسلة الحرفية، وهو ما يعني "" يعادل .Empty, ، ولكن لا يزال ليس بالسرعة .Length == 0.

.Length == 0 هو الخيار الأسرع، ولكن .Empty يجعل رمزًا أنظف قليلاً.

انظر مواصفات .NET لمزيد من المعلومات.

نصائح أخرى

ما هو الفرق بين السلسلة.

string.Empty هو حقل للقراءة فقط بينما "" هو ثابت وقت الترجمة.الأماكن التي يتصرفون فيها بشكل مختلف هي:

قيمة المعلمة الافتراضية في C# 4.0 أو أعلى

void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
    //... implementation
}

تعبير الحالة في بيان التبديل

string str = "";
switch(str)
{
    case string.Empty: // Error: A constant value is expected. 
        break;

    case "":
        break;

}

وسيطات السمة

[Example(String.Empty)]
// Error: An attribute argument must be a constant expression, typeof expression 
//        or array creation expression of an attribute parameter type

كانت الإجابات السابقة صحيحة لـ .NET 1.1 (انظر إلى تاريخ المنشور الذي ربطوه:2003).اعتبارًا من .NET 2.0 والإصدارات الأحدث، لا يوجد فرق جوهريًا.سينتهي JIT بالإشارة إلى نفس الكائن الموجود في الكومة على أية حال.

وفقًا لمواصفات C#، القسم 2.4.4.5:http://msdn.microsoft.com/en-us/library/aa691090(VS.71).aspx

كل سلسلة حرفية لا تؤدي بالضرورة إلى نسخة سلسلة جديدة.عندما تظهر سلسلتان حرفيتان أو أكثر متكافئتان وفقًا لعامل مساواة السلسلة (القسم 7.9.7) في نفس التجميع، تشير هذه السلسلة الحرفية إلى نفس مثيل السلسلة.

حتى أن أحدهم ذكر هذا في تعليقات منشور براد أبرام

باختصار، النتيجة العملية لـ "" مقابل.String.Empty صفر.سوف يكتشف JIT ذلك في النهاية.

لقد وجدت شخصيًا أن JIT أكثر ذكاءً مني ولذلك أحاول ألا أكون ذكيًا جدًا في تحسينات المترجمات الدقيقة مثل هذا.سوف يتكشف JIT عن حلقات for()، ويزيل التعليمات البرمجية الزائدة، والأساليب المضمنة، وما إلى ذلك بشكل أفضل وفي أوقات أكثر ملاءمة مما توقعته أنا أو مترجم C# من قبل.دع JIT يقوم بعمله :)

String.Empty هو يقرأ فقط المجال بينما "" هو مقدار ثابت.هذا يعني أنه لا يمكنك استخدامه String.Empty في بيان التبديل لأنه ليس ثابتا.

هناك اختلاف آخر وهو أن String.Empty ينشئ كود CIL أكبر.على الرغم من أن الكود المرجعي "" وString.Empty له نفس الطول، إلا أن المترجم لا يقوم بتحسين تسلسل السلاسل (راجع تعليمات إريك ليبرت مشاركة مدونة) للوسائط String.Empty.الوظائف المكافئة التالية

string foo()
{
    return "foo" + "";
}
string bar()
{
    return "bar" + string.Empty;
}

توليد هذا IL

.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 
}

الإجابات المذكورة أعلاه صحيحة من الناحية الفنية، ولكن ما قد ترغب حقًا في استخدامه، للحصول على أفضل إمكانية قراءة التعليمات البرمجية وأقل فرصة للاستثناء هو String.IsNullOrEmpty(s)

أنا أميل إلى استخدام String.Empty بدلا من "" لسبب واحد بسيط ولكنه غير واضح:"" و "" ليست متماثلة، فالأول يحتوي في الواقع على 16 حرفًا بعرض صفري.من الواضح أنه لن يقوم أي مطور مختص بوضع أحرف ذات عرض صفري في التعليمات البرمجية الخاصة به، ولكن إذا وصلوا إلى هناك، فقد يكون ذلك كابوسًا للصيانة.

ملحوظات:

  • إستعملت يو + فيف في هذا المثال.

  • لست متأكدًا مما إذا كانت SO ستأكل هذه الأحرف، لكن جرب ذلك بنفسك باستخدام أحد الأحرف العديدة ذات العرض الصفري

  • ولم أتوصل إلى هذا إلا بفضل https://codegolf.stackexchange.com/

يستخدم String.Empty بدلا من "".

يعد هذا مفيدًا للسرعة أكثر من استخدام الذاكرة ولكنه نصيحة مفيدة.ال "" هو حرفي لذلك سيكون بمثابة حرفي:عند الاستخدام الأول ، يتم إنشاءه وللاستخدامات التالية يتم إرجاع مرجعه.مثال واحد فقط من "" سيتم تخزينها في الذاكرة بغض النظر عن عدد المرات التي نستخدمها!لا أرى أي عقوبات الذاكرة هنا. المشكلة هي أنه في كل مرة "" يتم استخدام حلقة مقارنة للتحقق مما إذا كان "" موجود بالفعل في تجمع المتدربين. على الجانب الآخر، String.Emptyهي إشارة إلى أ "" المخزنة في منطقة ذاكرة .NET Framework. String.Empty يشير إلى نفس عنوان الذاكرة لتطبيقات vb.net و c#.فلماذا تبحث عن مرجع في كل مرة تحتاج إليها ""عندما يكون لديك هذا المرجع في String.Empty?

مرجع: String.Empty ضد ""

لا يقوم String.Empty بإنشاء كائن بينما يقوم "" بذلك.الفرق كما أشار هنا, ، ولكن تافهة.

كافة مثيلات "" هي نفسها، وهي عبارة عن سلسلة حرفية (أو ينبغي أن تكون كذلك).لذلك لن تقوم حقًا برمي كائن جديد على الكومة في كل مرة تستخدم فيها "" ولكن فقط تقوم بإنشاء مرجع لنفس الكائن الداخلي.بعد قولي هذا، أنا أفضل string.Empty.أعتقد أنه يجعل التعليمات البرمجية أكثر قابلية للقراءة.

string mystring = "";
ldstr ""

ldstr يدفع مرجع كائن جديد إلى سلسلة حرفية مخزنة في بيانات التعريف.

string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty

ldsfld يدفع قيمة الحقل الثابت إلى مكدس التقييم

أنا أميل إلى استخدام String.Empty بدلاً من "" لأن IMHO أكثر وضوحًا وأقل VB-ish.

القادمة من وجهة نظر إطار الكيان:يبدو أن إصدارات EF 6.1.3 تتعامل مع String.Empty و"" بشكل مختلف عند التحقق من الصحة.

يتم التعامل مع string.Empty كقيمة فارغة لأغراض التحقق من الصحة وسوف يؤدي إلى خطأ في التحقق من الصحة إذا تم استخدامه في حقل مطلوب (منسوب)؛حيث "" سوف يجتاز التحقق من الصحة ولن يلقي الخطأ.

قد يتم حل هذه المشكلة في EF 7+.مرجع:- https://github.com/aspnet/EntityFramework/issues/2610 ).

يحرر:[Required(AllowEmptyStrings = true)] سوف يحل هذه المشكلة، مما يسمح للسلسلة.Empty بالتحقق من صحتها.

نظرًا لأن String.Empty ليس ثابتًا في وقت الترجمة، فلا يمكنك استخدامه كقيمة افتراضية في تعريف الدالة.

public void test(int i=0,string s="")
    {
      // Function Body
    }

إريك ليبرت كتب (17 يونيو 2013):
"كانت الخوارزمية الأولى التي عملت عليها في برنامج التحويل البرمجي لـ C# هي المُحسِّن الذي يتعامل مع تسلسلات السلسلة. لسوء الحظ، لم أتمكن من نقل هذه التحسينات إلى قاعدة بيانات Roslyn قبل مغادرتي؛نأمل أن يصل شخص ما إلى ذلك!"

هنا بعض روزلين x64 النتائج اعتبارًا من يناير 2019.على الرغم من الملاحظات المتفق عليها للإجابات الأخرى في هذه الصفحة، لا يبدو لي أن x64 JIT الحالي يتعامل مع كل هذه الحالات بشكل مماثل، عندما يتم قول وفعل كل شيء.

ومع ذلك، لاحظ على وجه الخصوص أن واحدًا فقط من هذه الأمثلة ينتهي به الأمر بالاستدعاء String.Concat, ، وأعتقد أن هذا لأسباب صحة غامضة (على عكس مراقبة التحسين).ويبدو أن الاختلافات الأخرى أصعب في التفسير.


default(String)   +   { default(String)،   ""،   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

""   +   { default(String)،   ""،   String.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

String.Empty   +   { default(String)،   ""،   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

عندما تقوم بالمسح الضوئي عبر التعليمات البرمجية، تظهر "" ملونة بالطريقة التي يتم بها تلوين السلاسل.يبدو string.Empty وكأنه وصول عادي لأعضاء الفصل.خلال نظرة سريعة، من الأسهل اكتشاف "" أو استخلاص المعنى.

حدد السلاسل (لا يساعد تلوين تجاوز سعة المكدس تمامًا، ولكن في VS يكون هذا أكثر وضوحًا):

var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;

لقد قدم الجميع هنا بعض التوضيحات النظرية الجيدة.كان لدي شك مماثل.لذلك حاولت الترميز الأساسي عليه.ولقد وجدت الفرق.وهنا الفرق.

string str=null;
Console.WriteLine(str.Length);  // Exception(NullRefernceException) for pointing to null reference. 


string str = string.Empty;
Console.WriteLine(str.Length);  // 0

لذلك يبدو أن كلمة "Null" تعني فارغة تمامًا وأن كلمة "String.Empty" تعني أنها تحتوي على نوع ما من القيمة، ولكنها فارغة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top