Вопрос

Из-за ошибки, исправленной в 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 он не компилируется (бета 1 я не пробовал);Я усвоил это на собственном горьком опыте

Есть ли другой способ сделать this == null на чистом С#?

Это было полезно?

Решение

Это наблюдение было опубликовано на StackOverflow в Другой вопрос ранее сегодня.

Марк's отличный ответ на этот вопрос указывает, что согласно спецификации (раздел 7.5.7) у вас не должно быть доступа this в этом контексте и возможность сделать это в компиляторе C# 3.0 является ошибкой.Компилятор C# 4.0 работает правильно в соответствии со спецификацией (даже в бета-версии 1 это ошибка времени компиляции):

§ 7.5.7 Этот доступ

А этот доступ состоит из зарезервированного слова this.

этот доступ:

this

А этот доступ разрешено только в блокировать конструктора экземпляра, метода экземпляра или метода доступа к экземпляру.

Другие советы

Необработанная декомпиляция (Reflector без оптимизаций) двоичного файла режима отладки:

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
   .locals init (
        [0] string CS$1
    L_0000: ldloc.0 
    L_0001: call instance string CompilerBug.Program/Derived::CheckNull()
    L_0006: ret 
) 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
; CS$1<*> = CS$1<*>.CheckNull(); Label_0009: return CS$1<*>; } private string CheckNull() { string CS$1<*>; CS$1<*> = "Am I null? " + ((bool) (this == null)); Label_0017: return CS$1<*>; } }

Метод CompilerGenerated не имеет смысла; если вы посмотрите на IL (ниже), он вызывает метод с нулевой строкой (!).

<*>

В режиме Release локальная переменная оптимизируется, поэтому она пытается поместить несуществующую переменную в стек.

<*>

(Отражатель падает при превращении его в C #)

<Ч>

РЕДАКТИРОВАТЬ . Кто-нибудь (Эрик Липперт?) знает, почему компилятор генерирует ldloc ?

У меня было это! (и получил доказательства тоже)

alt text

Это не "ошибка". Это вы злоупотребляете системой типов. Вы никогда не должны передавать ссылку на текущий экземпляр ( 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);
    }

пример: UserID = CheckForNull (Request.QueryString [" UserID "], 147);

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top