سؤال

في العمل، أعمل بشكل متكرر على مشاريع حيث يجب تعيين خصائص عديدة لأشياء معينة أثناء بنائها أو في وقت مبكر من حياتها.من أجل الراحة وسهولة القراءة، غالبًا ما أستخدم With بيان لتعيين هذه الخصائص.أجد أن

With Me.Elements
    .PropertyA = True
    .PropertyB = "Inactive"
    ' And so on for several more lines
End With

تبدو أفضل بكثير من

Me.Elements.PropertyA = True
Me.Elements.PropertyB = "Inactive"
' And so on for several more lines

للبيانات الطويلة جدًا التي تقوم ببساطة بتعيين الخصائص.

لقد لاحظت أن هناك بعض المشكلات في الاستخدام With أثناء التصحيح؛لكن، كنت أتساءل عما إذا كانت هناك أي أسباب مقنعة لتجنب الاستخدام With في التمرين؟لقد افترضت دائمًا أن الكود الذي تم إنشاؤه عبر المترجم للحالتين المذكورتين أعلاه هو نفسه بشكل أساسي ولهذا السبب اخترت دائمًا كتابة ما أشعر أنه أكثر قابلية للقراءة.

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

المحلول

إذا كان لديك أسماء متغيرة طويلة وسينتهي الأمر بـ:

UserHandler.GetUser.First.User.FirstName="Stefan"
UserHandler.GetUser.First.User.LastName="Karlsson"
UserHandler.GetUser.First.User.Age="39"
UserHandler.GetUser.First.User.Sex="Male"
UserHandler.GetUser.First.User.Occupation="Programmer"
UserHandler.GetUser.First.User.UserID="0"
....and so on

ثم سأستخدمه لجعله أكثر قابلية للقراءة:

With UserHandler.GetUser.First.User
    .FirstName="Stefan"
    .LastName="Karlsson"
    .Age="39"
    .Sex="Male"
    .Occupation="Programmer"
    .UserID="0"
end with

في المثال الأخير، هناك فائدة أداء مقارنة بالمثال الأول لأنه في المثال الأول، أقوم بجلب المستخدم في كل مرة أقوم فيها بالوصول إلى خاصية مستخدم وفي حالة NOT أقوم بجلب المستخدم مرة واحدة فقط.

يمكنني الحصول على مكاسب الأداء دون استخدام، مثل هذا:

dim myuser as user =UserHandler.GetUser.First.User
myuser.FirstName="Stefan"
myuser.LastName="Karlsson"
myuser.Age="39"
myuser.Sex="Male"
myuser.Occupation="Programmer"
myuser.UserID="0"

لكنني سأختار عبارة "WTH" بدلاً من ذلك، فهي تبدو أنظف.

وقد أخذت هذا كمثال، لذلك لا تتذمر من فصل دراسي يحتوي على العديد من الكلمات الرئيسية، مثال آخر يمكن أن يكون مثل:مع RefundDialog.RefundDatagriView.SelectedRows(0)

نصائح أخرى

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

في .NET، يتم تجميعه إلى نفس التعليمات البرمجية تمامًا مثل تأهيل اسم الكائن بشكل كامل، لذلك لا توجد عقوبة أداء لهذا السكر.لقد تأكدت من ذلك من خلال تجميع فئة VB .NET 2.0 التالية ثم تفكيكها:

Imports System.Text

Public Class Class1
    Public Sub Foo()
        Dim sb As New StringBuilder
        With sb
            .Append("foo")
            .Append("bar")
            .Append("zap")
        End With

        Dim sb2 As New StringBuilder
        sb2.Append("foo")
        sb2.Append("bar")
        sb2.Append("zap")
    End Sub
End Class

التفكيك على النحو التالي -- لاحظ أن المكالمات إلى sb2Append الطريقة تبدو متطابقة مع With بيان يدعو ل sb:

.method public instance void  Foo() cil managed
{
  // Code size       91 (0x5b)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Text.StringBuilder sb,
           [1] class [mscorlib]System.Text.StringBuilder sb2,
           [2] class [mscorlib]System.Text.StringBuilder VB$t_ref$L0)
  IL_0000:  nop
  IL_0001:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.2
  IL_0009:  ldloc.2
  IL_000a:  ldstr      "foo"
  IL_000f:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0014:  pop
  IL_0015:  ldloc.2
  IL_0016:  ldstr      "bar"
  IL_001b:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0020:  pop
  IL_0021:  ldloc.2
  IL_0022:  ldstr      "zap"
  IL_0027:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_002c:  pop
  IL_002d:  ldnull
  IL_002e:  stloc.2
  IL_002f:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor()
  IL_0034:  stloc.1
  IL_0035:  ldloc.1
  IL_0036:  ldstr      "foo"
  IL_003b:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0040:  pop
  IL_0041:  ldloc.1
  IL_0042:  ldstr      "bar"
  IL_0047:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_004c:  pop
  IL_004d:  ldloc.1
  IL_004e:  ldstr      "zap"
  IL_0053:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0058:  pop
  IL_0059:  nop
  IL_005a:  ret
} // end of method Class1::Foo

لذا، إذا أعجبك، ووجدته أكثر قابلية للقراءة، فافعله؛لا يوجد سبب مقنع لعدم القيام بذلك.

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

هناك فرق بين استخدام With وإجراء إشارات متكررة إلى كائن ما، وهو أمر دقيق ولكن يجب أن يؤخذ في الاعتبار، على ما أعتقد.

عند استخدام عبارة "With"، فإنه يقوم بإنشاء متغير محلي جديد يشير إلى الكائن.المراجع اللاحقة التي تستخدم .xx هي مراجع لخصائص ذلك المرجع المحلي.إذا تم تغيير مرجع المتغير الأصلي أثناء تنفيذ عبارة NOT، فلن يتغير الكائن المشار إليه بواسطة جملة NOT.يعتبر:

Dim AA As AAClass = GetNextAAObject()
With AA
    AA = GetNextAAObject()

    '// Setting property of original AA instance, not later instance
    .SomeProperty = SomeValue
End With

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

الأمر كله يتعلق بسهولة القراءة.مثل كل السكر النحوي، يمكن أن يكون كذلك الإفراط في الاستخدام.

احتضنه إذا أنت تقوم بتعيين عدة أعضاء لكائن ما على بضعة أسطر

With myObject
  .Property1 = arg1
  .Property2 = arg2
...

يتجنب فعل أي شيء آخر مع "مع"

إذا كتبت كتلة تحتوي على 50-100 سطر وتتضمن الكثير من المتغيرات الأخرى، فقد يجعل من الصعب حقًا تذكر ما تم الإعلان عنه في الجزء العلوي من الكتلة.لأسباب واضحة، لن أقدم مثالاً على مثل هذه التعليمات البرمجية الفوضوية

حيثما يجعل الكود أكثر قابلية للقراءة، استخدمه.حيث يجعل ذلك أقل قابلة للقراءة، وتجنبها - على وجه الخصوص، أقترح عليك تجنب التداخل مع البيانات.

يحتوي الإصدار C# 3.0 على هذه الميزة فقط لتهيئة الكائن:

var x = new Whatever { PropertyA=true, PropertyB="Inactive" };

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

ملاحظة واحدة حول المثال الخاص بك - هل تحتاج حقًا إلى "أنا" على الإطلاق؟لماذا لا تكتب فقط:

PropertyA = True
PropertyB = "Inactive"

؟من المؤكد أن كلمة "أنا" متضمنة في هذه الحالة ...

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

UserHandler.GetUser.First.User.FirstName="Stefan"
UserHandler.GetUser.First.User.LastName="Karlsson"
UserHandler.GetUser.First.User.Age="39"
UserHandler.GetUser.First.User.Sex="Male"
UserHandler.GetUser.First.User.Occupation="Programmer"
UserHandler.GetUser.First.User.UserID="0"

فمن المحتمل أنك تنتهك قانون ديميتر

لا أستخدم VB.NET (كنت أستخدم VB العادي) ولكن...

هل النقطة الرائدة إلزامية؟إذا كان الأمر كذلك، فلا أرى مشكلة.في جافا سكريبت، نتيجة الاستخدام with هو أن خاصية الكائن تبدو تمامًا مثل المتغير العادي، و الذي - التي أمر خطير للغاية، حيث أنك لا ترى ما إذا كنت تقوم بالوصول إلى خاصية أو متغير، وبالتالي، with شيء يجب تجنبه.

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

أنا أتفق مع الردود الأخرى التي يجب عليك تجنب الاستخدام المتداخل لها with, ، لنفس السبب لتجنب with تماما في جافا سكريبت:لأنك لم تعد ترى الكائن الذي تنتمي إليه ممتلكاتك.

"مع" هو في الأساس "تتالي" من Smalltalk.إنه نمط في كتاب Kent Beck's Smalltalk Best Practice Patterns.

ملخص للنمط:استخدمه عندما يكون من المنطقي تجميع الرسائل المرسلة إلى الكائن.لا تستخدمه إذا حدث أن تم إرسال بعض الرسائل إلى نفس الكائن.

امتنع عن مع كتلة باي ثمن (حتى سهولة القراءة).سببان:

  1. ال وثائق مايكروسوفت حول بـ...انتهى بـ يقول أنه في بعض الظروف، يقوم بإنشاء نسخة من البيانات الموجودة على المكدس، لذلك سيتم التخلص من أي تغييرات تجريها.
  2. إذا كنت تستخدمه لاستعلامات LINQ، فإن نتائج lambda لا تكون متسلسلة وبالتالي يتم التخلص من نتيجة كل جملة وسيطة.

لوصف ذلك، لدينا مثال (مكسور) من كتاب مدرسي كان على زميلي في العمل أن يسأل المؤلف عنه (هذا غير صحيح بالفعل، لقد تم تغيير الأسماء للحماية...أيا كان):

مع dbcontext.Blahs
.OrderBy(الوظيفة(currentBlah)currentBlah.LastName)
.ThenBy(الوظيفة(currentBlah)currentBlah.الاسم الأول)
.حمولة()
انتهت ب

لدى OrderBy وThenBy بدون تأثير على الاطلاق.إذا قمت بإعادة تنسيق الكود عن طريق إسقاط "With" و"End With" فقط، وإضافة أحرف استمرار السطر في نهاية الأسطر الثلاثة الأولى...يعمل (كما هو موضح بعد 15 صفحة في نفس الكتاب المدرسي).

نحن لا نحتاج إلى أي سبب آخر لذلك ابحث و دمر مع كتل.لم يكن لديهم سوى معنى في فسر نطاق.

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

The data type of objectExpression can be any class or structure type or even a Visual Basic elementary type such as Integer. If objectExpression results in anything other than an object, you can only read the values of its members or invoke methods, and you get an error if you try to assign values to members of a structure used in a With...End With statement. This is the same error you would get if you invoked a method that returned a structure and immediately accessed and assigned a value to a member of the function’s result, such as GetAPoint().x = 1. The problem in both cases is that the structure exists only on the call stack, and there is no way a modified structure member in these situations can write to a location such that any other code in the program can observe the change.

يتم تقييم تعبير الكائن مرة واحدة، عند الدخول إلى الكتلة.لا يمكنك إعادة تعيين كائن expression من داخل الكتلة.

https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/with-end-with-statement

أعتقد أن المترجم كان من الممكن أن يكون أكثر ذكاءً قليلاً إذا قمت بتمرير اسم البنية باستخدام العبارة بدلاً من التعبير الذي يُرجع البنية، ولكن يبدو أنه ليس كذلك

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