قائمة شاملة بالفروق بين VB.NET و C #. الجزء 2

في الجزء الأول من المقالة ، وجد موضوع تفوق VB.NET على C # من حيث تصنيف TIOBE استجابة حيوية في التعليقات. لذلك ، بناءً على نصيحة AngReload ، دعنا ننظر إلى اتجاهات StackOverflow.

C # لا تزال قوية! تم إلغاء الثورة التي تحدثنا عنها منذ وقت طويل! الصيحة ، أيها الرفاق! أم لا؟ يعتمد تصنيف TIOBE على استفسارات محركات البحث ، ويستند تصنيف SO على علامات من الأسئلة المطروحة. ربما لا يعرف مطورو برنامج VB.NET ، الذي يضم العديد من الأشخاص الذين ليس لديهم تخصصات ، وجود StackOverflow؟ أو بعد أن وصلت إلى هناك من خلال Google ، أو حتى Bing ، لا تفهم كيفية طرح سؤال؟ أو ربما لديهم وثائق Miscrosoft كافية ، وتم بالفعل الإجابة على جميع الأسئلة القليلة.

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

محتوى


النص المخفي

التحولات



التعبيرات



التحولات


34. التحولات المنطقية


يؤدي تحويل Boolean True إلى أي نوع رقمي موقَّع إلى الحصول على -1 ، وإلى أي نوع غير موقَّع ، فإنه يعطي القيمة القصوى لهذا النوع ، بينما في C # لا توجد مثل هذه التحويلات. ومع ذلك ، فإن الأسلوب Convert.ToInt32 ، على سبيل المثال ، يحول True إلى 1 ، وهذه هي الطريقة التي يتم تمثيلها في الغالب في IL . في الاتجاه المعاكس ، يتم تحويل أي رقم بخلاف 0 إلى True .

لماذا؟ السبب الذي يجعل VB يفضل استخدامه من -1 إلى 1 هو أن السالب bitwise هو 0 (كل البتات مضبوطة على 0) في أي لغة هي -1 (جميع البتات مضبوطة على 1 ) ، لذا فإن استخدام هذه القيمة يجمع بين المنطقية و bitwise عمليات مثل And Or و Xor .
يتم أيضًا دعم التحويلات من وإلى السطور "صواب" و "خطأ" (بالطبع ، غير حساس لحالة الأحرف).

35. التحويلات بين أنواع التعداد وكذلك بين أنواع التعداد وأنواعها الأساسية غير محدودة تمامًا ، حتى إذا تم ضبط Option Strict على On


من وجهة نظر فلسفية ، تشير اللغة إلى أنواع Enum بدلاً من كونها مجموعة من الثوابت المسماة من نوع صحيح صحيح. إن المكان الأكثر وضوحا هو المساواة. يُسمح دائمًا بمقارنة أي عدد صحيح مع قيمة التعداد ، بينما في C # هذا يعطي خطأ.

قصة الوقت: لقد مرت Roslyn API بالعديد من المراجعات الداخلية. ولكن في كل منها ، تم تخصيص تعداد SyntaxKind لكل لغة ، والذي يخبرك ما هو بناء الجملة الذي تمثله العقدة (على سبيل المثال ، IfStatement ، TryCastExpression ). مرة واحدة ، استخدم أحد المطورين API التي حاولت SyntaxKind من اللغة SyntaxKind قيم SyntaxKind ، ولكن فقط باعتبارها Integer ، وبدون تلقي أخطاء عند مقارنة Integer و SyntaxKind الخام ، SyntaxKind هذا المطور فورًا إلى مكتبي واشتكى: "int is تفاصيل التنفيذ ، كان علي أن أجبر على القيام بأداء فريق! " .

على مر السنين ، خلال المراجعة التالية لواجهة برمجة التطبيقات ، قمنا بإزالة الخصائص بالكامل ( Property Kind As SyntaxKind ) ، والتي تشير إلى نوع خاص باللغة ، وبدأت جميع واجهات برمجة التطبيقات في إرجاع Integer . تم كسر كل رمز C # ، واستمرت جميع رموز VB في العمل كما لو لم يحدث شيء.

بعد ذلك بقليل ، قررنا إعادة تسمية هذه الخاصية إلى RawKind وإضافة طرق ملحق خاصة باللغة Kind() . تم كسر رمز C # لأن الأقواس كانت مطلوبة لاستدعاء طرق ، ولكن نظرًا لعدم الحاجة إليها في VB ، استمرت جميع رموز VB في العمل مرة أخرى كما لو لم يحدث شيء.

36. يتم التحكم بشكل كامل في بيئة التحويل البرمجي (إعدادات المشروع) في عملية التحقق من التدفق الزائد / السالب للقيمة الزائدة للحساب الصحيح ، لكن VB و C # يستخدمان قيمًا افتراضية مختلفة ؛ في VB ، يتم تمكين التحقق من تجاوز السعة بشكل افتراضي


تحتوي الأنواع المدمجة على نطاق ، لذلك ، على سبيل المثال ، يمكن أن تمثل Byte القيم من 0 إلى 255. فما الذي يحدث عند إضافة Byte 1 إلى Byte 255؟ إذا تم تعطيل التحقق من التدفق الزائد / تجاوز الحد الأدنى ، فتمرير القيمة إلى 0. إذا تم توقيع النوع ، يتم تمريره إلى أدنى رقم سالب (على سبيل المثال ، -128 لـ SByte ). يشير هذا على الأرجح إلى حدوث خطأ في البرنامج. إذا تم تمكين ميزة التحقق من التدفق الزائد / تجاوز الحد الأدنى ، يتم طرح استثناء. لفهم ما أعنيه ، ألقِ نظرة على هذه الحلقة غير الضارة.

 Module Program Sub Main() For i As Byte = 0 To 255 Console.WriteLine(i) Next End Sub End Module 

جيثب شفرة المصدر

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

حالة تجاوز السعة الأكثر شيوعًا هي ببساطة إضافة رقمين. خذ الأرقام 130 و 150 ، كلاهما Byte . إذا قمت بتجميعها ، فإن الإجابة هي 280 ، والتي لا تنسجم مع بايت. لكن المعالج الخاص بك لا يرى هذا. بدلاً من ذلك ، ذكر أن الإجابة 24.

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

ما هو الفرق؟ الأداء. يتطلب فحص CLR للفيضان وقتًا حسابيًا أكثر قليلاً مقارنة بخيار عدم التحقق ، مثل جميع عمليات الفحص الأمني ​​الأخرى. تعتمد VB على فلسفة أن إنتاجية المطورين أكثر أهمية من الأداء الحسابي ، لذلك بشكل افتراضي ، يتم تمكين التحقق الأمني. قد يتخذ فريق تطوير C # اليوم قرارًا مختلفًا بشأن الإعدادات الافتراضية للمشروع ، ولكن بالنظر إلى أن مطوري C # الأولين جاءوا من مطوري C / C ++ ، فربما تتطلب هذه المجموعة من الأشخاص أن الكود لا يفعل شيئًا أكثر ، مما قد يكلف دورات المعالج . هذا هو الفرق الفلسفي الصعب .

فارق بسيط: حتى إذا تم إيقاف تشغيل اختبار تجاوز السعة / تجاوز الحد الأدنى ، فإن تحويل NaN PositiveInfinity NegativeInfinity أو NegativeInfinity أو NegativeInfinity أو غير NaN من NaN Single أو Double إلى Decimal إلى استثناء ، حيث لا يمكن تمثيل أي من هذه القيم من حيث المبدأ في Decimal.

37. تحويل أرقام الفاصلة العائمة إلى عدد صحيح يستخدم المصرفيين التقريب بدلاً من الاقتطاع


إذا قمت بتحويل 1.7 إلى عدد صحيح في VB ، فستكون النتيجة 2. في C # ، ستكون النتيجة 1. لا أستطيع أن أقول أي شيء عن القواعد الرياضية خارج أمريكا ، لكن عندما أقوم بالتبديل من رقم حقيقي إلى عدد صحيح ، فإنني أقوم غريزيًا. ولا أحد ممن أعرفهم خارج دائرة المبرمجين يعتقدون أن أقرب عدد صحيح إلى 1.7 هو 1.

هناك بالفعل عدة طرق التقريب ، ونوع التقريب المستخدمة في VB (وفي طريقة Math.Round) يسمى التقريب المصرفي أو التقريب الإحصائيين بشكل افتراضي. جوهرها هو أنه بالنسبة للرقم الموجود في الوسط بين عددين ، تقريب VB إلى أقرب رقم زوجي. لذلك ، يتم تقريب 1.5 إلى 2 ، بينما يتم تقريب 4.5 إلى 4. ما هو في الواقع لا يعمل كما لو كنا نتعلم في المدرسة - لقد تعلمت الالتفاف من 0.5 (تقنيًا ، ومن الجولة إلى الجانب من الصفر). ولكن ، كما يوحي الاسم ، يتمتع التقريب المصرفي بميزة أنه مع وجود عدد كبير من العمليات الحسابية ، فإنك تنقسم عند التقريب إلى نصفين ، ولا تتخلى دائمًا عن الأموال أو تحتفظ بها دائمًا. بمعنى آخر ، في مجموعة كبيرة ، هذا يحصر تشوه البيانات في الانحراف الإحصائي النهائي.

من أين يأتي الفرق؟ التقريب أكثر سهولة وعملية ، حيث يتم اقتطاع أسرع. إذا كنت تفكر في استخدام VB في تطبيقات LOB ، وخاصة في التطبيقات مثل وحدات ماكرو Excel التي تعمل على VBA ، فإن مجرد إسقاط المنازل العشرية يمكن أن يسبب ... مشاكل.

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

38. ليس من الخطأ تحويل فئات NotInheritable إلى / من واجهات لا يتم تنفيذها في وقت الترجمة


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

لماذا؟ نشأ VB و COM معًا عندما كانا أطفالًا في الحي القديم. لذلك هناك العديد من الحلول في تصميم اللغة التي يولي فيها VB اهتمامًا كبيرًا للأشياء التي كانت موجودة فقط في COM في وقت إصدار .NET 1.0.

39. محاولة تفريغ (unbox) لاغية في نوع ذي معنى يؤدي إلى قيمة افتراضية للنوع ، وليس NullReferenceException


أعتقد أن هذا ينطبق أيضًا على الأنواع المرجعية ، ولكن نعم:
 CInt(CObj(Nothing)) = 0 

لماذا؟ لأن CInt(Nothing) = 0 ، وتميل اللغة إلى أن تكون متسقة إلى حد ما ، بغض النظر عما إذا كنت قد كتبت متغيراتك أم لا. وهذا ينطبق على أي هيكل ، وليس فقط أنواع ذات معنى مدمجة. انظر الأساس المنطقي في # 25 لمزيد من التفاصيل.

40. يدعم Unboxing تحويلات النوع البدائي


في كل من VB و C # يمكنك تحويل Short إلى Integer ، لكن ماذا لو حاولت تحويل Short إلى Integer المعبأة؟ في VB Short سيتم تفريغه أولاً ثم تحويله إلى Integer . في C # ، إلا إذا قمت بفك الشفرة يدويًا قبل التحويل إلى int ، فسيتم طرح InvalidCastException .
ينطبق هذا على جميع التحويلات الداخلية ، أي الأنواع الرقمية المحزومة ، والتحويلات بين السلاسل وأنواع الأرقام ، السلاسل والتواريخ (نعم ، عشري وتاريخ أنواع بدائية).

لماذا؟ مرة أخرى ، لضمان سلوك ثابت ، سواء تمت كتابة برنامجك بالكامل ، أو كتابته ككائن ، أو تتم إعادة بيعه من خيار إلى آخر. انظر # 39 أعلاه.

41. هناك تحويلات بين String و Char


  • String تحويل String إلى Char ، والتي تمثل أول حرف لها.
  • Char تحويل Char إلى String بالطريقة المعقولة الوحيدة.

لأنه لا أحد باستثناءي يتذكر بناء جملة حرفي في VB (ولا ينبغي).

42. هناك تحويلات بين String و Char


  • String تحويل String إلى صفيف Char تتألف من جميع أحرفها.
  • يتم تحويل صفيف Char إلى String تتكون من جميع عناصرها.

للحصول على الدقة: هذه التحويلات تنشئ كائنات جديدة ، لا يمكنك الوصول إلى بنية String الداخلية.

قصة مضحكة: لقد عثرت ذات مرة (أو ربما أبلغت عنها ، وأنا بحثت) على كسر التغيير بين .NET 3.5 و 4.0 ، لأن فريق .NET أضاف بين هذه الإصدارات معدل ParamArray إلى String.Join التحميل الزائد String.Join الثانية ، والتي تأخذ مجموعة من السلاسل . يتم فقد الافتراضات الدقيقة في الوقت المناسب (ربما للأفضل) ، لكن ، كما أعتقد ، السبب هو أنه باستخدام مُعدل ParamArray يمكنك الآن تحويل صفيف Char إلى سلسلة وتمريرها كعنصر منفصل إلى صفيف المعلمة. موضوع المرح.

43 و 44. التحويلات من السلسلة إلى أنواع الأرقام والتاريخ تدعم بناء الجملة الحرفية (عادةً)


  • CInt("&HFF") = 255
  • CInt("1e6") = 1_000_000
  • CDate("#12/31/1999#") = #12/31/1999#

يعمل هذا مع بادئات الأساس ويجعل من الممكن استخدام طريقة ملائمة للغاية لتحويل الإدخال السداسي عشري (أو الثماني) إلى رقم: CInt("&H" & input) . لسوء الحظ ، هذا التناظر مهين في وقت كتابة هذا التقرير لأنه لم يتم تحديث وقت تشغيل VB لدعم البادئة الثنائية & B أو 1_000 المجموعة المكون من 1_000 ، لكنني آمل أن يتم إصلاح ذلك في الإصدار التالي. يعمل الترميز العلمي ، ولكن بدون لاحقات الكتابة ، كما تدعم تحويلات التاريخ تنسيقات التاريخ القياسية ، لذلك يعمل تنسيق JSON المستخدم في ISO-8601 أيضًا: CDate("2012-03-19T07: 22Z") = #3/19/2012 02:22:00 AM#

لماذا؟ لا أعرف أي سبب آخر غير الراحة. لكنني أود حقًا تقديم الدعم للتنسيقات الشائعة الأخرى الموجودة في كل مكان تقريبًا في الشبكة اليوم ، مثل #FF و U + FF و 0xFF. أعتقد أن هذا يمكن أن يسهل إلى حد كبير الحياة في بعض أنواع التطبيقات ...

45. لا توجد تحويلات بين أنواع Char و integer


ماذا؟!؟!؟
بعد قراءة كل هذه التحولات الإضافية ، هل أنت متفاجئ؟ يمنع VB التحويلات بين Char و Integer :

  • CInt("A"c) لا يتم ترجمة.
  • CChar(1) لا يتم ترجمة.

لماذا؟ ليس من الواضح ما الذي سيحدث. عادةً ما تستخدم VB في مثل هذه المواقف نهجًا عمليًا و / أو حدسيًا ، ولكن للتعبير CInt("1") أعتقد أن نصف القراء يتوقعون الرقم 1 (قيمة الحرف 1) ، ويتوقع النصف الرقم 49 (رمز ASCII / UTF لـ الحرف 1). بدلاً من اتخاذ الاختيار الخاطئ في نصف الحالات ، لدى VB وظائف خاصة لتحويل الأحرف إلى رموز ASCII / Unicode والعكس ، AscW و ChrW على التوالي.

التعبيرات


46. ​​لا شيء


لا يعني الحرفي في VB لاغية . تعني "القيمة الافتراضية للنوع الذي يتم استخدامه من أجله" ، ويحدث هذا فقط لأن القيمة المرجعية فارغة. الفرق مهم فقط عند استخدامه في سياق:

  1. لا شيء يأخذ نوعًا مهمًا ، و ...
  2. ليس واضحًا من السياق أنه يفعل ذلك.

دعونا نلقي نظرة على بعض الأمثلة التي توضح ما يعنيه هذا.

الأول ، ربما غريب بعض الشيء ، لكنني لا أعتقد أن معظم الناس سيتم تفجيرهم بفهم أن هذا البرنامج سوف يطبع "صحيح":

 Module Program Sub Main() Dim i As Integer = 0 If i = Nothing Then Console.WriteLine("True") End If End Sub End Module 

جيثب شفرة المصدر

السبب بسيط للغاية: فأنت تقارن Integer (0) بالقيمة الافتراضية لنوعها (أيضًا 0). المشكلة تحدث في VB2005 / 2008 عند إضافة أنواع ذات معنى nullable. ألقِ نظرة على هذا المثال:

  Module Program Sub Main() Dim i = If(False, 1, Nothing) End Sub End Module 

جيثب شفرة المصدر

مفهومة ، كيف يمكن لشخص أن يقترح أن النوع i هو Integer? ( Nullable(Of Integer) ). ولكن هذا ليس كذلك ، لأن Nothing يحصل على النوع من السياق ، والنوع الوحيد في هذا السياق يأتي من المعامل الثاني ، وهذا هو non-nullable Integer بسيط non-nullable Integer (من الناحية الفنية ، Nothing يوجد Nothing الإطلاق من النوع). هناك طريقة أخرى لإلقاء نظرة على هذه المشكلة تتمثل في المثال التالي:

 Module Program Sub Main() M(Nothing) End Sub Sub M(i As Integer) Console.WriteLine("Non-nullable") End Sub Sub M(i As Integer?) Console.WriteLine("Nullable") End Sub End Module 

جيثب شفرة المصدر

مرة أخرى ، هنا ، بشكل حدسي ، يبدو أن Nothing يضيف تلميحًا "لاغى عنه" وأن اللغة تختار حملًا زائدًا يقبل nullable ، لكنه لا (يحدد non-nullable ، لأنه "أكثر تحديدًا"). كحد أدنى ، يمكن افتراض أنه ، مثل null في C # ، لا ينطبق تعبير Nothing على Integer ، وأن الحمل الزائد nullable سيتم اختياره بواسطة طريقة الاستثناء ، ولكن هذا يعتمد مرة أخرى على فكرة خاطئة بأن Nothing = null (Is null?) .

فارق بسيط: تمت إضافة تعبير default جديد في C # 7.1 يطابق Nothing في VB. إذا قمت بإعادة كتابة الأمثلة الثلاثة المذكورة أعلاه في C # باستخدام default بدلاً من القيمة null ، فستحصل على نفس السلوك تمامًا .

ما الذي يمكن عمله حيال ذلك؟ هناك العديد من الاقتراحات ، لكن لم يفز أي منها بعد:

  • إظهار تحذير في كل مرة Nothing تحويل Nothing إلى نوع ذي مغزى وهو ليس null في نوع مهم null .
  • قم بتوسيع جميل Nothing to 0 ، 0.0 ، ChrW(0) ، False ، #1/1/0001 12:00:00 AM# ChrW(0) #1/1/0001 12:00:00 AM# أو New T (القيمة الافتراضية لأي بنية) في كل مرة تكون قيمتها في وقت التشغيل واحدة من المدرجة أعلاه.
  • أضف بناء جملة جديدًا يعني "Null ، لا ، حقًا!" مثل Null أو Nothing?
  • أضف بناء جملة جديد في شكل لاحقة (؟) تلتف القيمة في nullable للمساعدة في استنتاج النوع ، على سبيل المثال If(False, 0?, Nothing)
  • أضف عوامل تشغيل تحويل لاغية للأنواع المضمّنة لتسهيل إعطاء تلميحات لكتابة الاستدلال ، على سبيل المثال ، If (False, CInt? (0), Nothing)

أود أن أسمع أفكارك في التعليقات و / أو على تويتر .

لتلخيص:

  • الأوقات السابقة - VB6 و VBA لها "لا شيء" ، "لاغٍ" ، "فارغ" و "مفقود" ، وهذا يعني أشياء مختلفة.
  • 2002 - في VB.NET لا يوجد Nothing سوى (القيمة الافتراضية في سياق معين) ، وفي C # - null فقط.
  • 2005 - تضيف C # القيمة default(T) (القيمة الافتراضية للنوع T ) ، لأن الأدوية المضافة حديثًا تخلق موقفًا تحتاج إلى تهيئة قيمة فيه ، لكنك لا تعرف ما إذا كان نوعًا مرجعيًا أو مهمًا ؛ VB لا يفعل شيئًا لأن هذا البرنامج النصي مغلق بالفعل بواسطة Nothing .
  • 2017 - تضيف C # القيمة default (القيمة default في السياق) حيث يوجد العديد من السيناريوهات التي يكون فيها تحديد T زائداً أو مستحيلاً

يواصل VB مقاومة إضافة تعبير Null (أو ما يعادله) بسبب:

  • سيتم بناء الجملة كسر التغيير.
  • بناء الجملة لن يكسر التغيير ، لكن اعتمادًا على السياق سيعني أشياء مختلفة.
  • سيكون بناء الجملة غير واضح للغاية (على سبيل المثال ، Nothing? ) ؛ تخيل أنك بحاجة إلى التحدث بصوت عالٍ حول Nothing ولا Nothing? لشرح شيء لشخص.
  • قد يكون بناء الجملة قبيحًا جدًا (على سبيل المثال ، Nothing? ).
  • تم إغلاق البرنامج النصي للتعبير الخالي بالفعل بواسطة Nothing ، وستكون هذه الوظيفة زائدة عن الحاجة في معظم الأوقات.
  • في كل مكان ، يجب تحديث جميع الوثائق وجميع التعليمات للتوصية باستخدام بناء الجملة الجديد ، الذي يعلن بشكل أساسي أنه Nothing عتيق بالنسبة لمعظم البرامج النصية.
  • لن يتصرف Nothing ولا Nothing كما هو في وقت التشغيل فيما يتعلق بالربط المتأخر والتحولات وما إلى ذلك.
  • يمكن أن يكون مثل بندقية في طعن.

شيء من هذا القبيل.

الحمل والولادة

فيما يلي مثال مشابه جدًا للمثال أعلاه ، ولكن بدون الاستدلال على النوع:

 Module Program Sub Main() Dim i As Integer? = If(False, 1, Nothing) Console.WriteLine(i) End Sub End Module 

جيثب شفرة المصدر

يعرض هذا البرنامج 0. يتصرف تمامًا كما في المثال الثاني ، لنفس السبب ، ولكنه يوضح مشكلة منفصلة ، وإن كانت ذات صلة. بشكل حدسي ، ما هو Dim i as Integer? = If(False, 1, Nothing) Dim i as Integer? = If(False, 1, Nothing) يتصرف مثل Dim i As Integer? : If False Then i = 1 Else i = Nothing Dim i As Integer? : If False Then i = 1 Else i = Nothing . في هذه الحالة ، هذا ليس كذلك ، لأن التعبير الشرطي (If) لا "يمر" المعلومات من النوع الأخير إلى معاملاته. اتضح أن هذا يعطل كل التعبيرات في VB التي تعتمد على ما يسمى الكتابة النهائية (السياقية) ( Nothing ، AddressOf ، مجموعة من الحرفيات ، وتعبيرات lambda والسلاسل المحرفية) بمشاكل تتراوح من عدم التجميع بشكل عام إلى إنشاء قيم غير صحيحة بهدوء إلى رمي بصوت عالٍ استثناءات. فيما يلي مثال للخيار غير المترجم:

 Module Program Sub Main() Dim i As Integer? = If(False, 1, Nothing) Console.WriteLine(i) Dim operation As Func(Of Integer, Integer, Integer) = If(True, AddressOf Add, AddressOf Subtract) End Sub Function Add(left As Integer, right As Integer) As Integer Return left + right End Function Function Subtract(left As Integer, right As Integer) As Integer Return left - right End Function End Module 

جيثب شفرة المصدر

هذا البرنامج لن يجمع. بدلاً من ذلك ، يُبلغ عن خطأ في تعبير If أنه لا يمكن تحديد نوع التعبير عندما يكون كل من تعبيرات AddressOf مقصودًا AddressOf لتلقي Func(Of Integer, Integer, Integer) .

, Nothing null (), Nothing nullability () If(,,) Nothing ( ) () — , .

47. ;


«3»:

 Module Program Sub Main() Dim i As Integer = 3 M((i)) Console.WriteLine(i) End Sub Sub M(ByRef variable As Integer) variable = -variable End Sub End Module 

GitHub

C# «-3». , VB — , . , M(3) , M(i) , i , . C# ( ) , M .

? VB . Quick Basic (Copyright 1985), . , 2002 , .

№1: « » , Visual Basic .NET.
№2: Roslyn ( , ( ) ( )), : . C# , ((a + b) * c a + (b * c)) . , C#, C++, , , , . : « VB?» « C#?» source.roslyn.ioBoundParenthesized VB C#. , , .

48. Me


VB.NET Me . , - , — , Me Structure . Me . C# this , this .

49.


VB, , :

 Class C Sub M() Extension() End Sub End Class Module Program Sub Main() End Sub <Runtime.CompilerServices.Extension> Sub Extension(c As C) End Sub End Module 

GitHub

C# ( something.Extension). , C#, , this.Extension() .

? , 'Me.' , , , , . VB.NET . , .

50. (Static imports will not merge method groups)


VB « » (Java-, C# VB). , Imports System.Console WriteLine() . 2015 C# . VB Shared- , System.Console System.Diagnostics.Debug , WriteLine , . C# , , .

? , , VB , C# ( ). , ( , ), … , .

, VB , VB , , , , , ( #6 ). VB . , VB 2002 .

51 52. (Partial-name qualification & Smart-name resolution)


:

  • , — ( ). System System.Windows.Forms — , , System System.Windows System.Windows System.Windows.Forms .
  • , , , . System Windows , Windows Form .

, , . . VB Imports , using C# .

, VB System , System , System . , . , ExtensionAttribute , <Runtime.CompilerServices.Extension> <System.Runtime.CompilerServices.Extension> .

C# . using System System.Threading Threading .

, C# , . , System , System.Threading Threading . , , , , .

, , VB, C# , Imports / using , C# using , , using .

(Quantum Namespaces) ( )

, ! VB , . , System ComponentModel System.Windows.Forms ComponentModel ? ComponentModel . , ComponentModel.PropertyChangedEventArgs , ( , ). System.Windows.Forms (, , , , ), (ambiguity errors).

VB2015 (Smart Name Resolution), System System.Windows.Forms ComponentModel , , System.ComponentModel System.Windows.Forms.ComponentModel , . , , , , . , , , .. ComponentModel.PropertyChangedEventArgs
System.ComponentModel.PropertyChangedEventArgs , System.Windows.Forms.ComponentModel.PropertyChangedEventArgs . , .

, Windows , ( ) ( ) ( ). WinForms/WPF UWP .

53. Add


#33 , VB - , . , , — , :

 Class Contact Property Name As String Property FavoriteFood As String End Class Module Program Sub Main() Dim contacts = New List(Of Contact) From { {"Leo", "Chocolate"}, {"Donnie", "Bananas"}, {"Raph", "The Blood of his Enemies"}, {"Mikey", "Pizza"} } End Sub <Runtime.CompilerServices.Extension> Sub Add(collection As ICollection(Of Contact), name As String, favoriteFood As String) collection.Add(New Contact With {.Name = name, .FavoriteFood = favoriteFood}) End Sub End Module 

GitHub

C# , Roslyn C#, . , ( , ), VS2015.

54. ,


, VB Dim buffer(expression) As Byte Dim buffer = New Byte(expression) {} expression + 1 .

Microsoft BASIC, DIM ( dimension — ). , , , : 0 expression. Microsoft BASIC 1 ( , 1984), ( ), 2002 .

, - , , VB , BASIC C , , C, C- . , buffer(10) 0 10, 9!

55. VB - , C#


, . , VB ( ) , — . :

  • CType({1, 2, 3}, Short()) CType(New Integer() {1, 2, 3}, Short ()) , Integer Short .
  • CType({1, 2, 3}, Short()) New Short() {1, 2, 3} . .

, , VB , C#. , :

  • Dim empty As Integer() = {}

:

  • Dim array As Predicate(Of Char)() = {AddressOf Char.IsUpper, AddressOf Char.IsLower, AddressOf Char.IsWhitespace}

( ):

  • Dim byteOrderMark As Byte() = {&HEF, &HBB, &HBF} ' .

, IList(Of T) , IReadOnlyList(Of T) , ICollection(Of T) , IReadOnlyCollection(Of T) IEnumerable(Of T) , , , ParamArray IEnumerable .

? , VB. , . 2008 VB C# «» {}, - ( , , ). , , , + , . .

56.


, LINQ. , .

, , .

57. CType, DirectCast C#


/ VB C#.
VB CType :

  • ;
  • ( );
  • , , Long Integer (. «»);
  • (unboxes) ;
  • ;
  • ( CTypeDynamic ).

VB DirectCast :

  • ;
  • ;
  • ( Integer Byte );
  • ;
  • ( );
  • .

C# — (Type)expression :

  • ;
  • ;
  • ;
  • ;
  • ;
  • .

CType C# , . , . VB C# , IL . , C#, , . .

, CType , (, ). CType , DirectCast , . , , IL : Object ( ValueType ) CLR «unbox» VB-, , (, Short Integer ). , , C#. . , .

? . , , , , .

58. «»


, , 5 Mod 2 * 3 5 VB, «» C# 5 % 2 * 3 3.

, , . , (, (\) VB), , , . !

59. ; + & ; + VB <> + C#


, + () & () VB + C#.
String :
VB

  • “1” + 1 = 2.0
  • “1” & 1 = “11”

C#

  • «1» + 1 == «11»

, + &
VB

  • “obj: “ + AppDomain.CurrentDomain ' Error: + not defined for String and AppDomain.
  • ”obj: “ & AppDomain.CurrentDomain ' Error: & not defined for String and AppDomain.
  • ”obj: “ + CObj(AppDomain.CurrentDomain) ' Exception, no + operator found.
  • ”obj: “ & CObj(AppDomain.CurrentDomain) ' Exception, no & operator found.

C#

  • «obj: » + AppDomain.CurrentDomain == «obj: » + AppDomain.CurrentDomain.ToString()
  • «obj: » + (object)AppDomain.CurrentDomain == «obj: » + AppDomain.CurrentDomain.ToString()
  • «obj: » + (dynamic)AppDomain.CurrentDomain == «obj: » + AppDomain.CurrentDomain.ToString()

:
VB

  • 1 + 1 = 2
  • 1 & 1 = “11”

C#

  • 1 + 1 == 2

String Enum:
VB

  • “Today: ” + DayOfWeek.Monday ' Exception: String «Today: » cannot be converted to Double.
  • “Today: ” & DayOfWeek.Monday = “Today: 1”
  • “Today: ” & DayOfWeek.Monday.ToString() = “Today: Monday”

C#

  • «Today: » + DayOfWeek.Monday == «Today: Monday»

: , + VB, - . + , , - . لماذا؟ :

  • “10” — “1” = 9.0,
  • “5” * “5” = 25.0,
  • “1” << “3” = 8,
  • “1” + 1 = 2.0,
  • “1” + “1” = “11”

. — .

: +, . , &, , ( , ). , , .

60. : 3 / 2 = 1,5


— : « ?» . «». : « . ?»
VB C#.

C, , , « 5 9?» , \. , , , , 0 ( , - INumeric ).

61. ^ Math.Pow


Math.Pow . , . , ( custom ) ( , System.Numerics.BigInteger ).

: F# **, VB F# : op_Exponent op_Exponentiation . F# Pow . . , .

62. =/<> /


C# '==' () , , ( ). VB . VB ( Is/IsNot ) .

: - Roslyn , . . . VB , = , C# , , , .

63. =/<> ( )


VB .

-, ( ) - ( ), , Option Compare Binary Option Compare Text . Option Compare Binary , , VS.

( ), , API. :

  • /: “A” = “a”/“A” <> “a”
  • : “A” > “a”
  • Select Case: Select Case “A” : Case “a”

:

  • Equals: “A”.Equals(“a”)
  • Contains: ”A”.Contains(“a”)
  • Distinct: From s In {“A”, “a”} Distinct

, , : VB . , Option Compare , «Empty».

 Module Program Sub Main() Dim s As String = Nothing If s = "" Then Console.WriteLine("Empty") End If End Sub End Module 

GitHub

s = "" VB — String.IsNullOrEmpty(s) .
, , , , , . , , .

? Option Compare Text , , . , , .
, , , , .

, , . , . , , (collation) SQL Server, . , VB VB6, VBA Office, Excel Access, VBScript Windows, -, -… . , , .NET API , Option Compare Text, . , .NET API, .

null, , . VB6 . String "". , VB String . VB, Left Mid , String . null . Len(CStr(Nothing)) = 0 Left(CStr(Nothing) , 5) = "" , CStr(Nothing).Length CStr(Nothing).Trim() .

, ? . ( ).

:
, , , . ! VB , , "String A" = "String B" , Microsoft.VisualBasic.CompilerServices.Operators.CompareString , - , , . LINQ- . , VB ( ). , , - , . LINQ-to-SQL, LINQ-to-Entities , Microsoft. , VB , !

, C#, VB, LINQ . : 1) , VB , , 2) , VB , , LINQ-. , VB ().

: , « API». Option Compare VB, InStr.Replace Microsoft.VisualBasic.Strings . , ?

, , , ? , , , : , , .

64. Nullable ( null )


VB C# - nullable. , (null-propagation).

SQL, , , null. , (, +), null, null. "?." : obj?.Property obj null, null, .

nullable , VB, C# . - : .

VB, nullable , null, null . 1 + null null null + null null. , (, = <>) C#:

  • VB, Is/IsNot , Boolean?
  • C# (==, !=, >, <, >=, <=) bool bool?

VB ( nullable ) null null . Boolean = Boolean? , True , False null . . C# non-nullable bool , .

, . null. VB NULL = NULLNULL , TRUE.
, :

. Null , , , C# .

. C# VB, « null?» C# (if (value == null)) . VB , VB (=/<>) (Is/IsNot) , VB Is Nothing non-nullable Boolean .

, VB null, null. And/AndAlso Or/OrElse .

Integer? ( ), VB, C# null, :

  • 1 AND NULL NULL
  • 1 OR NULL NULL

Boolean? , VB .

  • FALSE AND NULL FALSE
  • TRUE OR NULL TRUE
  • TRUE AND NULL NULL
  • FALSE OR NULL NULL

, True/False , , null. , AndAlso OrElse .

C# (&&/||) (&/|) nullable boolean (bool?) . , , non-nullable boolean nullable boolean .

?
VB , - :

 Imports System.ComponentModel Class BindableRange Implements INotifyPropertyChanged Property _EndDate As Date? Property EndDate As Date? Get Return _EndDate End Get Set(value As Date?) ' This line here: If value = _EndDate Then Return _EndDate = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(EndDate))) End Set End Property Public Event PropertyChanged As PropertyChangedEventHandler _ Implements INotifyPropertyChanged.PropertyChanged End Class Module Program WithEvents Range As New BindableRange Sub Main() Range.EndDate = Today Range.EndDate = Today Range.EndDate = Nothing Range.EndDate = Nothing End Sub Private Sub BindableRange_PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _ Handles Range.PropertyChanged Console.WriteLine(e.PropertyName & " changed.") End Sub End Module 

GitHub

, , , , «EndDate change» . , , VB null ? , EndDate , , , Nothing .

VB : «, , . » :
 If value <> _EndDate Then _EndDate = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(EndDate))) End If 

! . , non-nullable . , . , :
 If value Is Nothing AndAlso _EndDate Is Nothing Then Return If value <> _EndDate Then Return 

?
, C# , VB. ( nullable , ), , null.

null — «» « » . .

null « » «» . , , : comparer, , comparer . Roslyn, Optional(Of T) , , , null, , .

, NULL « », VB :

  • , « , ?» « ».
  • : « , ?» « ».

, , SQL- . , NULL SQL , NULL. . , , NULL . , . , , ( ). , , , , , NULL , SQL ( ).

VB. nullable 2008 , VB ?
LINQ to SQL

VB , , , , , , LINQ- . !

. SQL Server, , SET ANSI_NULLS OFF , SQL- C#, WHERE Column = NULL . , , OFF ( ). SQL Server ( ) . : « ? . , - Option ANSI_NULLS Off VB.NET?» . :



, , , , , SQL Server, VB.
شيء من هذا القبيل.

65. 1:1


, VB , , , . VB - , .

, , , , . VB , , , , , VB .

9.8.4 .

66. Function() a = b () => a = b


. , () => expression C# Function() expression VB. Function() -, - , VB. a = b , a b ( Boolean ), b . - (delegate relaxation) VB ( -) Sub- ( ). . () => a = b C# VB — Sub() a = b . — - , .

=, , . ( Sub -) , ( Function -) .

67. Async Function async void


C# async -, , , Task void , , Task , .

VB.NET , .. void Async Async Sub , Task Task(Of T)Async Function . , , VB, (relaxing) Task Async void . Async Sub , , .

68. () VB


, VB:

 Class Foo 'Function [Select](Of T)(selector As Func(Of String, T)) As Foo ' Return Me 'End Function Function Where(predicate As Func(Of String, Boolean)) As Integer Return 0 End Function End Class Module Program Sub Main() Dim c As New Foo Dim q = From x In c Where True Select x End Sub End Module 

GitHub

VB, C#. -, Foo Select , , Where . Select , , Select , Integer . C# , .Where ( Select ). , , .

LINQ API. , VB C#, . , C# , « », , , , . - , «» , , -.

, VB , , C# , .

, Roslyn, : « (range variables)?» « ?» . . , VB , Let , C# — . , VB, C# 2012 , :

 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CSharpExamples { struct Point { public int X { get { return 0; } } public int Y { get { return 0; } } } class Foo { public IEnumerable<Point> Select<T>(Func<string, T> selector) { return new Point[0]; } } static class Program { static void Main(string[] args) { var c = new Foo(); var q = from X in c let Y = "" select Y.CompareTo(-1); } } } 

GitHub

, — ? X, — string . let Y , string. , Point, X Y , , int X Y , «» . Y select , int int `, … .

, « ?» . VS2015 C# , «». , Roslyn C#, . , ( , ), - .

? , , , . , , VB C# .

69 70. As From cast ; 'As'


( , …)

From x As Integer In y VB, , from int x in y C#.

-, C# , ( ) . .Cast<T>() . VB , , , , .

-, , .Cast ( ). , , , .Cast .Select .

? . VB . , For Each x As T In collection , As T . From As For Each ( , As ).

71-75. Select , ,


على سبيل المثال:

  • From x In y Where x > 10 . , Select .
  • From x In y Select x Where x > 10 .
  • From x In y Select x , From x In y Select x = x , xx , xSelect . Select .
  • From x In y Select z = x.ToString() , x .
  • From x In y Select x.FirstName , From x In y Select FirstName = x.FirstName .
  • From x In y Select x.FirstName, x.LastNameFrom x In y Select New With {x.FirstName, y.LastName} , , . IEnumerable(Of $AnonymousType$) , .

? ( Amanda Silver ). !

  • , Select , SQL , Select , . LINQ VB Select , SQL, From .
  • , , .
  • , Select , SQL, - - . VB comma separated ( ) -.
  • , Select , , , , , , , — .

? , , - , , :

 Module Program Sub Main() Dim numbers = {1, 2, 3} ' BC36606: Range variable name cannot match the name of a member of the 'Object' class. Dim q = From n In numbers Select n.ToString() End Sub End Module 

GitHub

BC36606: Range variable name cannot match the name of a member of the 'Object' class BC30978: Range variable '…' hides a variable in an enclosing block or a range variable previously defined in the query expression — , Object , , , , . ( n.ToString() ), . , .

76+.


. … … . … 20-25 ( — .. ).

دقيقة من الإعلانات. 15-16 - .NET- DotNext 2019 Piter . , . , . .

Source: https://habr.com/ru/post/ar445580/


All Articles