مترجم C# يلقي خطأ في الوسائط غير الصالحة.لماذا؟

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

  •  06-07-2019
  •  | 
  •  

سؤال

لدي فصل يحتوي على طريقتين مثل هذه:

public String getFoo(Int32 a)
{
  return getBar(a, "b", null);
}

public String getBar(Int32 a, String b, Int32 c)
{
  //do something
  return "";
}

ولكن عندما أقوم بتجميع صفي أحصل على خطأين:

  1. أفضل مطابقة للطريقة المحملة بشكل زائد لـ getBar(int,string,int) تحتوي على بعض الوسائط غير الصالحة
  2. الوسيطة "3":لا يمكن التحويل من "<null>"إلى" كثافة العمليات "

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

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

شكرًا.

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

المحلول

في .NET، يوجد مفهوم مميز بين أنواع المراجع وأنواع القيم.

النوع المرجعي هو كائن تم تخصيصه في الكومة (سيكون فئة فرعية من System.Object).كل ما هو موجود في المكدس هو مؤشر لهذا الكائن.ولهذا السبب، من الصحيح تمامًا تخزين مؤشر فارغ.

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

لا يمكن أن تكون أنواع القيم فارغة.

معظم أنواع C# البدائية هي أنواع قيمة.السلسلة هي نوع خاص من البدائي وهو في الواقع نوع مرجعي.

في .NET 2.0، أضاف MS القدرة على إحاطة نوع عام داخل البنية بحيث يمكنه محاكاة نوع لاغٍ.ما يحدث حقًا هو أن المنطق الموجود داخل بنية Nullable<T> يحاكي قيمة فارغة بالنسبة لك.

وقد عبروا عنها باستخدام اختصار نحوي بإضافة علامة استفهام إلى النوع، على سبيل المثال:

int? nullableInt = null;
float? nullableFloat = null;

إلخ...

إذا كنت لا تحب كثافة العمليات؟بناء الجملة، يمكنك دائمًا استخدام Nullable<SomeType>

public String getBar(Int32 a, String b, Nullable<Int32> c)

كملاحظة جانبية، أفضل إضافة حمل زائد عند القيام بما تفعله، فقط لجعل بناء الجملة أجمل.

public String getBar(Int32 a, String b)
{
     this.getBar(a,b,null);
}

public String getBar(Int32 a, String b, Nullable<Int32> c)
{
}

نصائح أخرى

حاول إجراء الوسيطة الثالثة لـ getBar كثافة العمليات لاغية.

وبالتالي فإن التوقيع سيكون بهذا الشكل:

public String getBar(Int32 a, String b, Int32? c)

يمكنك معرفة المزيد حول الأنواع الخالية في .NET هنا و هنا.

Int32 هو نوع القيمة، وهو ما يعني null ليست وسيطة صالحة لمعلمات النوع Int32.

إذا كنت حقًا بحاجة إلى قيمة ints لاغية، فاستخدم int? يكتب.

الخطأان اللذان تراهما هما في الواقع نفس الخطأ.

صني صحيح.
Int32 هو نوع قيمة ولا يمكنه الاحتفاظ بالقيمة "فارغة".إذا كنت بحاجة إلى تمرير "null" كقيمة معلمة، فاستخدم Nullable بدلاً من Int32 كنوع الوسيطة.

يمكنك العثور على مزيد من المعلومات في أنواع لاغية (دليل البرمجة C#) على MSDN.

Int32 هو اسم مستعار لـ int وهو نوع ذو قيمة/غير قابل للإلغاء.للحصول على نسخة لاغية منه، استخدم System.Nullable أو ببساطة "int؟".

لا تنس أيضًا التحويل مرة أخرى إلى قيمة int غير فارغة:

int? nullable = ...;
int non_nullable = nullable??0; 

حيث يشير الرقم إلى القيمة التي يجب أن يتحملها إذا كان فارغًا بالفعل.

لا يمكن أن يكون Int32 فارغًا.اجعله نوعًا لاغٍ بدلاً من ذلك:

public String getBar(Int32 a, String b, Int32? c)
{
    if (c.HasValue)
    {
        ...do something with c.Value...
    }
    return "";
}

حسنا اذا خمسةاقترح سبعة أشخاص int? كحل.أقترح حلين آخرين ذلك قد أن تكون أكثر ملاءمة، تبعاً للحالة؛

  • خلق الزائد للطريقة التي تحتوي على وسيطتين فقط، وحذف null عند الاتصال:

    public String getFoo(Int32 a)
    {
      return getBar(a, "b", null);
    }
    
    public String getBar(Int32 a, String b)
    {
      //do something else, without the int
    }
    

    على الرغم من أنك ربما لا ترغب في القيام بذلك لأنك ذكرت أنك تريد تجنب تكرار التعليمات البرمجية.

  • يستخدم default بدلاً من null:

    return getBar(a, "b", default(int));
    

    بالمناسبة، هذا هو نفس تمرير القيمة 0.

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