في الجزء
الأول من المقالة ، وجد موضوع تفوق 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
لاغية . تعني
"القيمة الافتراضية للنوع الذي يتم استخدامه من أجله" ، ويحدث هذا فقط لأن القيمة المرجعية فارغة. الفرق مهم فقط عند استخدامه في سياق:
- لا شيء يأخذ نوعًا مهمًا ، و ...
- ليس واضحًا من السياق أنه يفعل ذلك.
دعونا نلقي نظرة على بعض الأمثلة التي توضح ما يعنيه هذا.
الأول ، ربما غريب بعض الشيء ، لكنني لا أعتقد أن معظم الناس سيتم تفجيرهم بفهم أن هذا البرنامج سوف يطبع "صحيح":
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
GitHubC# «-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.io —
BoundParenthesized
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
GitHubC# ( 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
GitHubC# , 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#, + &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()
:VBC#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
GitHubs = "" 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 =
NULL —
NULL , 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?)
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
GitHubVB,
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
, x
— x
, x
— Select
. 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.LastName
— From 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}
GitHubBC36606: 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 . , . , . .