هل من الممكن استخدام المشغل ؟؟ ورمي استثناء جديد ()؟

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

سؤال

لدي عدد من الطرق التي تفعلها بعد ذلك:

var result = command.ExecuteScalar() as Int32?;
if(result.HasValue)
{
   return result.Value;
}
else
{
   throw new Exception(); // just an example, in my code I throw my own exception
}

أتمنى أن أتمكن من استخدام المشغل ?? مثله:

return command.ExecuteScalar() as Int32? ?? throw new Exception();

لكنه يولد خطأ التجميع.

هل من الممكن إعادة كتابة الكود الخاص بي أم أن هناك طريقة واحدة فقط للقيام بذلك؟

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

المحلول

ل C# 7

في C# 7 ، throw يصبح تعبيرًا ، لذلك من الجيد استخدام الكود الموضح في السؤال بالضبط.

لـ C# 6 وما قبل

لا يمكنك فعل ذلك مباشرة في C# 6 وأوائل - المعامل الثاني ؟؟ يحتاج إلى أن يكون تعبيرا ، وليس بيان رمي.

هناك بعض البدائل إذا كنت تحاول حقًا العثور على خيار موجز:

يمكنك الكتابة:

public static T ThrowException<T>()
{
    throw new Exception(); // Could pass this in
}

وثم:

return command.ExecuteScalar() as int? ?? ThrowException<int?>();

أنا هل حقا لا تنصح بأن تفعل ذلك ... إنه أمر فظيع للغاية.

ماذا عن طريقة التمديد:

public static T ThrowIfNull(this T value)
{
    if (value == null)
    {
        throw new Exception(); // Use a better exception of course
    }
    return value;
}

ثم:

return (command.ExecuteScalar() as int?).ThrowIfNull();

بديل آخر (مرة أخرى طريقة تمديد):

public static T? CastOrThrow<T>(this object x) 
    where T : struct
{
    T? ret = x as T?;
    if (ret == null)
    {
        throw new Exception(); // Again, get a better exception
    }
    return ret;
}

الاتصال مع:

return command.ExecuteScalar().CastOrThrow<int>();

إنه قبيح إلى حد ما لأنه لا يمكنك تحديد int? كحجة نوع ...

نصائح أخرى

كما قيل ، لا يمكنك القيام بذلك مع ؟؟ المشغل (حسنًا ، لا يخلو من بعض التشوهات التي لا تتناسب مع هدفك المتمثل في جعل هذا المنظف).

عندما أرى هذا النمط الناشئ أفكر على الفور إنفاذ. في الأصل من عالم C ++ الذي ينقلونه إلى C# بشكل جيد ، على الرغم من أنه يمكن القول أنه أقل أهمية في معظم الأوقات.

الفكرة هي أنك تأخذ شيء من النموذج:

if( condition )
{
  throw Exception;
}

ويحولها إلى:

Enforce<Exception>( condition );

(يمكنك تبسيط المزيد عن طريق التخلف عن نوع الاستثناء).

أخذها إلى أبعد من ذلك ، يمكنك كتابة مجموعة من الأساليب على غرار Nunit لفحوصات حالة مختلفة ، على سبيل المثال ؛

Enforce<Exception>.NotNull( obj );
Enforce<Exception>.Equal( actual, expected );
Enforce<Exception>.NotEqual( actual, expected );

إلخ.

أو الأفضل من ذلك من خلال توفير توقعات Lamba:

Enforce<Exception>( actual, expectation );

ما هو أنيق حقًا هو أنه بمجرد القيام بذلك ، يمكنك إعادة فِعلي بارام وفرض في النسق:

return Enforce( command.ExecuteScalar() as Int32?, (o) => o.HasValue ).Value;

... ويبدو أن هذا هو الأقرب إلى ما تتبعه.

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

إنه مدرج في قائمة الأشياء التي يجب القيام بها لتطبيق تطبيق مفتوح المصدر.

إذا كنت تريد فقط استثناء عندما لا تكون القيمة التي تم إرجاعها Int32 ثم افعل هذا:

return (int)command.ExecuteScalar();

إذا كنت ترغب في رمي استثناءك المخصص ، فربما أفعل شيئًا كهذا بدلاً من ذلك:

int? result = command.ExecuteScalar() as int?;
if (result == null) throw new YourCustomException();
return result.Value;

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

يعمل مشغل الفحم الخالي من ذلك: إذا كانت القيمة اليسرى للمشغل لاغية ، فأعادتها ؛ خلاف ذلك ، أعد ما هو على يمين المشغل. ال throw الكلمة الرئيسية لا تُرجع قيمة ؛ وبالتالي ، لا يمكن استخدامه على الجانب الأيمن من المشغل.

السبب الذي لا يمكنك فعله:

return command.ExecuteScalar() as Int32? ?? throw new Exception();

هو لأن رمي استثناء هو بيان ، وليس تعبير.

إذا كنت تتطلع فقط إلى تقصير الكود قليلاً ، فربما هذا:

var result = command.ExecuteScalar() as Int32?;
if(result.HasValue) return result;
throw new Exception();

لا حاجة لآخر.

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