(هذا == فارغ) في C#!
-
05-07-2019 - |
سؤال
بسبب خطأ تم إصلاحه في C# 4، تتم طباعة البرنامج التالي true
.(جربه في LINQPad)
void Main() { new Derived(); }
class Base {
public Base(Func<string> valueMaker) { Console.WriteLine(valueMaker()); }
}
class Derived : Base {
string CheckNull() { return "Am I null? " + (this == null); }
public Derived() : base(() => CheckNull()) { }
}
في VS2008 في وضع الإصدار، فإنه يطرح InvalidProgramException.(في وضع التصحيح، يعمل بشكل جيد)
في VS2010 Beta 2، لا يتم تجميعه (لم أجرب Beta 1)؛تعلمت هذا بصعوبة
هل هناك أي طريقة أخرى لجعل this == null
في C # النقي؟
المحلول
تم نشر هذه الملاحظة على StackOverflow في سؤال آخر في وقت سابق من اليوم.
مارك'س إجابة عظيمة على هذا السؤال يشير إلى أنه وفقًا للمواصفات (القسم 7.5.7)، من المفترض ألا تتمكن من الوصول this
في هذا السياق والقدرة على القيام بذلك في برنامج التحويل البرمجي C# 3.0 يعد خطأً.يتصرف مترجم C# 4.0 بشكل صحيح وفقًا للمواصفات (حتى في الإصدار التجريبي 1، يعد هذا خطأ في وقت الترجمة):
§ 7.5.7 هذا الوصول
أ هذا الوصول يتكون من الكلمة المحجوزة
this
.هذا الوصول:
this
أ هذا الوصول لا يجوز إلا في حاجز لمنشئ المثيل، أو أسلوب المثيل، أو موصل المثيل.
نصائح أخرى
ووبتفريغ الخام (العاكس مع عدم وجود تحسينات) من ثنائي وضع التصحيح هو:
private class Derived : Program.Base
{
// Methods
public Derived()
{
base..ctor(new Func<string>(Program.Derived.<.ctor>b__0));
return;
}
[CompilerGenerated]
private static string <.ctor>b__0()
{
string CS$1$0000;
CS$1$0000 = CS$1$0000.CheckNull();
Label_0009:
return CS$1$0000;
}
private string CheckNull()
{
string CS$1$0000;
CS$1$0000 = "Am I null? " + ((bool) (this == null));
Label_0017:
return CS$1$0000;
}
}
وطريقة CompilerGenerated لا معنى له. إذا نظرتم إلى IL (أدناه)، فإنه استدعاء الأسلوب على باطل <م> سلسلة م> (!).
.locals init (
[0] string CS$1$0000)
L_0000: ldloc.0
L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
L_0006: stloc.0
L_0007: br.s L_0009
L_0009: ldloc.0
L_000a: ret
في وضع الإصدار، هو الأمثل لمتغير محلي بعيدا، لذلك يحاول دفع متغير غير existant إلى المكدس.
L_0000: ldloc.0
L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
L_0006: ret
و(أعطال العاكس عند تحويله إلى C #)
تعديل : في؟ لا أحد (؟ اريك ليبرت) أعرف لماذا المترجم تنبعث ldloc
ولقد كان ذلك! (وحصلت على دليل ايضا)
وهذه ليست "علة". هذا هو أنت إساءة استخدام النظام نوع. كنت أبدا المفترض لتمرير إشارة إلى الحالة الراهنة (this
) إلى أي شخص داخل المنشئ.
وأنا يمكن أن يخلق "علة" مماثل من قبل استدعاء أسلوب الظاهري داخل منشئ الفئة الأساسية أيضا.
وفقط لأنك <م> يمكن م> تفعل شيئا سيئا لا يعني لها لعلة عندما تحصل قليلا منه.
ويمكن أن أكون مخطئا، ولكن أنا متأكد إذا الكائن هو null
هناك أبدا سيكون سيناريو حيث ينطبق this
.
وعلى سبيل المثال، كيف ندعو CheckNull
؟
Derived derived = null;
Console.WriteLine(derived.CheckNull()); // this should throw a NullReferenceException
ولست متأكدا إذا كان هذا هو ما كنت تبحث عن
public static T CheckForNull<T>(object primary, T Default)
{
try
{
if (primary != null && !(primary is DBNull))
return (T)Convert.ChangeType(primary, typeof(T));
else if (Default.GetType() == typeof(T))
return Default;
}
catch (Exception e)
{
throw new Exception("C:CFN.1 - " + e.Message + "Unexpected object type of " + primary.GetType().ToString() + " instead of " + typeof(T).ToString());
}
return default(T);
}
وعلى سبيل المثال: معرف المستخدم = CheckForNull (Request.QueryString [ "معرف المستخدم"]، 147)؛