لماذا لا يجب أن أستخدم أنواعًا لاغية دائمًا في C#

StackOverflow https://stackoverflow.com/questions/830592

  •  06-07-2019
  •  | 
  •  

سؤال

لقد كنت أبحث عن بعض التوجيه الجيد حول هذا الأمر منذ تقديم المفهوم في .NET 2.0.

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

هل هناك ضربة "مهمة" لاختيار نوع بيانات قابلة للإلغاء على نظيره غير القابل للفرق؟

أنا أفضل أن أتحقق من قيمي مقابل NULL بدلاً من Guid.Empty ، string.empty ، dateTime.minvalue ، <= 0 ، etc ، والعمل مع الأنواع المطلقة بشكل عام. والسبب الوحيد الذي يجعلني لا أختار الأنواع الباطلة في كثير من الأحيان هو الشعور بالحكة في الجزء الخلفي من رأسي الذي يجعلني أشعر أنه أكثر من التوافق المتخلف الذي يفرض ذلك "؟" حرف للسماح صراحة بقيمة فارغة.

هل هناك أي شخص دائمًا ما يختار (الأكثر دائمًا) أنواعًا قابلة للإلغاء بدلاً من الأنواع غير القابلة للفرق؟

شكرا على وقتك،

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

المحلول

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

List<int> list = new List<int>()
int c = list.Count;

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

أنت محق تمامًا في الحالات التي تكون فيها القيمة اختيارية. إذا كان لدينا وظيفة قد تُرجع أو لا تُرجع سلسلة ، فإعادة فارغة. لا ترجع string.empty (). لا تعيد "القيم السحرية".

ولكن ليست كل القيم اختيارية. وجعل كل شيء اختياري يجعل بقية الكود الخاص بك أكثر تعقيدًا (يضيف مسارًا رمزًا آخر يجب معالجته).

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

نصائح أخرى

لأنه من غير المريح دائمًا التحقق مما إذا كان النوع الباطئ هو null.

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

// nice and simple, this will always work
int a = myInt;

// compiler won't let you do this
int b = myNullableInt;

// compiler allows these, but causes runtime error if myNullableInt is null
int c = (int)myNullableInt;
int d = myNullableInt.Value;    

// instead you need to do something like these, cumbersome and less readable
int e = myNullableInt ?? defaultValue;
int f = myNullableInt.HasValue ? myNullableInt : GetValueFromSomewhere();

أعتقد أن مصممي اللغة يشعرون أن "الأنواع المرجعية التي لاغية بشكل افتراضي" كانت خطأً ، وأن غير القابلين عنيفًا هو الافتراضي الوحيد المعقول ، ويجب عليك الاشتراك في الفرق. (هكذا هو في العديد من اللغات الوظيفية الحديثة.) "NULL" عادة ما يكون كومة من المتاعب.

يبدو أن لديك سؤالين مختلفين ...

لماذا أرغب في استخدام أنواع البيانات غير القابلة للفرق في C#؟

بسيطة ، لأن البيانات من نوع القيمة التي تعتمد عليها مضمونة من قبل المترجم ليكون لها قيمة!

لماذا لا أختار أنواعًا قابلة للإلغاء بشكل افتراضي ، وأستخدم الأنواع غير المميزة فقط عندما يكون ذلك منطقيًا بشكل صريح؟

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

بالطبع ، عندما تأتي بياناتك من أي مكان ليس البرنامج الخاص بك ، فإن جميع الرهانات متوقفة. أفضل مثال هو من قاعدة بيانات. يمكن أن تكون حقول قاعدة البيانات null, ، لذلك تريد أن يحاكي متغير البرنامج الخاص بك هذه القيمة - وليس فقط إنشاء قيمة "سحرية" (أي -1 أو 0 أو أي شيء آخر) null. يمكنك القيام بذلك مع أنواع لاغية.

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

يتم تفضيل القيم الخالية من قبل العديد من مصممي قواعد البيانات ومبرمجي قاعدة بيانات SQL ولكن مع تغيير بسيط في التفكير في المشكلة التي يمكنك التخلص منها مع القيم الخالية ولديها بالفعل رمز أبسط وأكثر موثوقية (على سبيل المثال ، لا تقلق بشأن NullReferenceExceptionس).

هناك بالفعل طلب كبير على "ر!" المشغل الذي يجعل أي نوع مرجعي غير قابل للفرق ، على غرار كيف "t؟" يجعل أنواع القيمة Nullable ، وتمنى أندرس Hejlsberg ، مخترع C#، أنه شمل القدرة.

انظر أيضا السؤال ، لماذا يوجد "فارغ" في C# و Java؟

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

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

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

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