سؤال

قراءة وهو أسرع؟ByVal أو ByRef؟ جعلني أتساءل عما إذا كانت التعليقات الموجودة هناك تنطبق على Strings من حيث الأداء.نظرًا لأنه يتم نسخ السلاسل قبل تمريرها، أليس من الأكثر كفاءة (إذا كان المستدعى لا يحتاج إلى نسخة من دورة السلسلة) تمرير السلاسل ByRef?

شكرًا،
CFP.

يحرر: خذ بعين الاعتبار هذا الكود، الذي جعلني أعتقد أن هناك نوعًا ما من النسخ يحدث:

Sub Main()
    Dim ByValStr As String = "Hello World (ByVal)!"
    Dim ByRefStr As String = "Hello World (ByRef)!"

    fooval(ByValStr)
    fooref(ByRefStr)

    Console.WriteLine("ByVal: " & ByValStr)
    Console.WriteLine("ByRef: " & ByRefStr)

    Console.ReadLine()
End Sub


Sub fooval(ByVal Str As String)
    Str = "foobar"
End Sub

Sub fooref(ByRef Str As String)
    Str = "foobar"
End Sub

يخرج:

ByVal: Hello World (ByVal)!
ByRef: foobar
هل كانت مفيدة؟

المحلول

سلاسل غير صحيح منسوخ قبل أن يتم تمريره.السلاسل هي أنواع مرجعية، على الرغم من أنها تتصرف مثل أنواع القيم إلى حد ما.

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

من المؤكد تقريبًا أن هذا شيء لا داعي للقلق بشأنه، وأشك في وجود فرق كبير في الأداء على الإطلاق.الموقف الوحيد الذي أستطيع أن أرى فيه أي فرصة للفارق هو عند التمرير كبير أنواع القيمة.

نصائح أخرى

قررت التحقق من ذلك بنفسي للحصول على إجابة "علمية" أكثر.إنهم متشابهون.إذا استخدمت الكود أدناه، فسيكون ByVal أبطأ بنسبة 2٪ تقريبًا من ByRef.ومع ذلك، إذا قمت بتبديلها، بحيث أقوم بتوقيت ByRef قبل ByVal، فإن ByRef يكون أبطأ بنسبة 2٪ تقريبًا.لذا، ما يهم في الواقع أكثر من ByRef أو ByVal في هذه الحالة هو الترتيب الذي يتم تشغيلهما به :)

Function CreateString()

    Dim i As Integer
    Dim str As String = ""

    For i = 1 To 10000
        str = str & "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    Next i

    Return str
End Function

Sub fooval(ByVal Str As String)
    Str = Str & "foobar"
End Sub

Sub fooref(ByRef Str As String)
    Str = Str & "foobar"
End Sub

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    Dim str As String = CreateString()
    Dim stopWatch As New Stopwatch
    Dim i As Integer

    stopWatch.Start()
    For i = 1 To 1000
        fooval(str)
    Next i
    stopWatch.Stop()
    Dim valtime As Long = stopWatch.ElapsedMilliseconds

    stopWatch.Restart()
    For i = 1 To 1000
        fooref(str)
    Next i
    stopWatch.Stop()
    Dim reftime As Long = stopWatch.ElapsedMilliseconds

    MsgBox("Val took " & valtime & " milliseconds and Ref took " & reftime & " milliseconds")
End Sub

لفهم سلوك أنواع الفئات، بما في ذلك السلاسل، يجب مراعاة جميع معلمات نوع الفئة والمتغيرات والحقول وعناصر المصفوفة، وما إلى ذلك.كعقد "معرفات الكائنات".لو Foo هو متغير من النوع string, ، البيان Foo = 12345.ToString(); سيتم إنشاء معرف كائن جديد (افتراضيًا، معرف الكائن # 197)، وإنشاء كائن جديد من النوع string بهذا المعرف، الذي يحمل الأحرف الخمسة "12345".سيتم بعد ذلك تخزينها Object ID#197 في المتغير Foo.إذا قام أحد باستدعاء روتين بمعلمة غير مرجعية param, ، ويمر Foo إليها إذن param سيكون عقد متغير محلي Object ID #197.البيان param += "6"; من شأنه إنشاء كائن جديد (على سبيل المثالمعرف الكائن #521)، من النوع سلسلة، يحمل الأحرف الستة "123456" وتخزينها Object ID #521 داخل param.لاحظ أن Foo لا يزال يحمل Object ID#197, ، ولا يزال هذا الكائن يحتفظ بالسلسلة المكونة من خمسة أحرف "12345".

لو param قد تم تمريرها ref, ، ثم البيان param += "6" سيكون مخزنا Object ID #521 داخل Foo.لا يزال من غير الممكن أن يتسبب في أي تغيير ملحوظ في الكائن رقم 197، باستثناء ربما جعله مؤهلاً لجمع البيانات المهملة (إذا Foo كان المرجع الوحيد إلى الكائن رقم 197، فإن الكتابة فوقه تعني أنه لن يكون هناك أي إشارة إلى هذا الكائن في أي مكان في الكون).

لاحظ أنه من السهل عمومًا التفكير في أنواع الفئات غير القابلة للتغيير مثل string, ، حتى بدون التفكير في معرفات الكائنات، نظرًا لأن الطريقة الوحيدة لتغيير تسلسل الأحرف التي يمثلها متغير سلسلة هي تخزين معرف كائن مختلف هناك.ومع ذلك، يصبح التفكير فيما يتعلق بمعرفات الكائنات أمرًا ضروريًا عند التعامل مع أنواع الفئات القابلة للتغيير.تمرير متغير من نوع الفئة Car, ، وليس عن طريق المرجع، سيكون معادلاً لنسخ رقم VIN من قصاصة ورق إلى أخرى، وتسليم القصاصة الأخيرة من الورق لبعض عمال المتجر، ومطالبتهم بفعل شيء ما بها.إذا حددت الورقة الأولى في الأصل سيارة حمراء تحمل رقم VIN#15934، فعند انتهاء العمال، قد تحدد الورقة الأولى سيارة زرقاء تحمل رقم VIN#15934، ولكنها ستكون نفس السيارة.لا شيء يستطيع العمال فعله بقصاصة الورق التي حصلوا عليها، ولا أي شيء يمكنهم فعله بالسيارة، من شأنه أن يغير السيارة التي أشارت إليها الورقة الأولى.من ناحية أخرى، فإن تمرير المعلمة حسب المرجع سيكون أشبه بقطعة من الورق مكتوب عليها رقم VIN لعمال المتجر، واستعادة الورقة منهم عند الانتهاء.إذا تمكن العمال من شطب رقم VIN وكتابة رقم آخر، فعند إعادة قصاصة الورق قد يشير ذلك إلى نفس السيارة أو سيارة مختلفة؛إذا كانت تشير إلى سيارة مختلفة، فقد تكون السيارة التي أشارت إليها في الأصل قد تم تعديلها أو لا، والسيارة التي تشير إليها الورقة في النهاية قد تحمل أو لا تحمل أي تشابه مع السيارة الأصلية.

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