Почему компилятор по крайней мере не предупреждает об этом == ноль

Вот очень читаемая функция vimscript, которая хорошо справляется со всеми случаями,

  • ведет себя подобно встроенному :bd (если только одно окно, просто вызовите его!), выполните предупреждение и ничего не делать, если буфер модифицирован. если нет другого буфера, создайте его через :enew. если существует альтернативный буфер и в buffer-list, переключитесь на него, иначе идите дальше, через :bn.
  • более разумное поведение для макета нескольких окон, не закрывающее ни одного окна, всегда остается в исходном окне. для каждого окна, отображающего текущий буфер, выполните указанные выше действия, а затем удалите старый текущий буфер.
nnoremap <Leader>b :call DeleteCurBufferNotCloseWindow()<CR>

func! DeleteCurBufferNotCloseWindow() abort
    if &modified
        echohl ErrorMsg
        echom "E89: no write since last change"
        echohl None
    elseif winnr('$') == 1
        bd
    else  " multiple window
        let oldbuf = bufnr('%')
        let oldwin = winnr()
        while 1   " all windows that display oldbuf will remain open
            if buflisted(bufnr('#'))
                b#
            else
                bn
                let curbuf = bufnr('%')
                if curbuf == oldbuf
                    enew    " oldbuf is the only buffer, create one
                endif
            endif
            let win = bufwinnr(oldbuf)
            if win == -1
                break
            else        " there are other window that display oldbuf
                exec win 'wincmd w'
            endif
        endwhile
        " delete oldbuf and restore window to oldwin
        exec oldbuf 'bd'
        exec oldwin 'wincmd w'
    endif
endfunc
21
задан Andrei Rînea 17 March 2010 в 16:41
поделиться

4 ответа

Потому что вы можете переопределить operator == , чтобы вернуть истину для этого случая.

public class Foo
{
    public void Test()
    {
        Console.WriteLine(this == null);
    }

    public static bool operator ==(Foo a, Foo b)
    {
        return true;
    }

    public static bool operator !=(Foo a, Foo b)
    {
        return true;
    }
}

Запуск new Foo (). Test () выведет на консоль «True».

Другой вопрос: почему компилятор не выдает предупреждение для ReferenceEquals (this, null) ? Внизу приведенной выше ссылки:

Распространенной ошибкой при перегрузках operator == является использование (a == b) , (a == null ) или (b == null) , чтобы проверить равенство ссылок. Вместо этого это приводит к вызову перегруженного оператора == , что вызывает бесконечный цикл. Используйте ReferenceEquals или приведите тип к Object, чтобы избежать цикла.

Что на может ответить ответ @Aaronaught. И именно поэтому вы должны делать (object) x == null или ReferenceEquals (x, null) , а не выполнять простой x == null , когда вы проверяете наличие нулевых ссылок. Если, конечно, вы не уверены, что оператор == не перегружен.

31
ответ дан 16 October 2019 в 23:29
поделиться

На самом деле, условие действительно может быть выполнено, по крайней мере в Visual Studio 2008. Они исправили это поведение в VS 2010, но не исключено, что существует и другой способ создания такого условия.

(tl;dr версия - в C# 3.5 законно ссылаться на this из анонимной функции, переданной в качестве аргумента конструктора, но если вы действительно попытаетесь это использовать, вы обнаружите, что this является null.)

.
4
ответ дан 16 October 2019 в 23:29
поделиться

Это также согласуется с другими предупреждениями, которые C # делает (или не делает в этом отношении), например:

if(true)
or 
if(1 == 1)

Они также всегда будут иметь один и тот же результат, нет от того, что.

2
ответ дан 16 October 2019 в 23:29
поделиться

Вау ... Думаю, я был постыдно неправ

Я не согласен. Я думаю, вы все еще хорошо замечаете.

Компилятор знает, будет ли сравнение идти к определяемому пользователем оператору сравнения или нет, а компилятор знает, что в противном случае 'this' никогда не будет нулевым.

И действительно, компилятор отслеживает, может ли данное выражение юридически быть нулевым или нет, чтобы реализовать небольшую оптимизацию для вызовов невиртуальных методов. Если у вас есть невиртуальный метод M и вы говорите foo.M (); , то компилятор генерирует это как «сделать виртуальный вызов M с приемником foo». Почему? Потому что мы хотим выбросить, если foo имеет значение null, а виртуальный вызов всегда выполняет нулевую проверку получателя. Невиртуальный вызов - нет; нам пришлось бы сгенерировать его как «проверить foo на null, а затем выполнить невиртуальный вызов M», что является более длинным, медленным и более раздражающим кодом.

Теперь, если мы можем уйти, не выполнив нулевую проверку, мы это сделаем. Если вы скажете this.M () или (new Foo ()). M () , то мы НЕ генерируем виртуальный вызов. Мы генерируем не виртуальный вызов без нулевой проверки, потому что знаем, что он не может быть нулевым.

Таким образом, у компилятора есть отличные данные о том, будет ли конкретное сравнение с нулевым значением иногда, всегда или никогда не будет успешным.

Тогда возникает вопрос: «Если компилятор знает, что конкретное сравнение никогда не будет успешным, почему бы не сгенерировать для него предупреждение?»

И ответ: «Иногда мы делаем, а иногда нет».

Мы поступаем в этой ситуации:

int x = 123;
if (x == null) ...

Существует оператор равенства, определенный для двух целых чисел, допускающих значение NULL. x можно преобразовать в int, допускающий значение NULL. null можно преобразовать в int, допускающий значение NULL. Таким образом, этот оператор равенства действителен, поэтому используется и, конечно же, всегда ложен. Компилятор выдает предупреждение, что выражение всегда ложно.

Однако из-за ошибки, которую мы случайно представили в C # 3, этот код НЕ выдает этого предупреждения:

Guid x = whatever;
if (x == null) ...

То же самое. Обнуляемый оператор равенства guid действителен, но предупреждение подавляется. Я не уверен, исправили ли мы эту ошибку для C # 4 или нет. Если нет, надеюсь, мы добавим его в пакет обновления.

Что касается "if (this == null)", я не знаю, почему мы не предупреждаем об этом. Это определенно кажется хорошим кандидатом на предупреждение. Наиболее вероятное объяснение состоит в том, чтобы следовать этому логическому силлогизму:

  • предупреждения - это особенности компилятора
  • функции компилятора должны быть (1) продуманы, (2) разработаны, (3) реализованы, (4) протестированы, (5) задокументированы и (6) отправлены вам, прежде чем вы сможете воспользоваться этой функцией.
  • Никто не сделал ни одного из шести необходимых вещей для этой функции; мы не можем поставлять функции, о которых даже не думали.
  • Следовательно, такой функции нет.

Есть бесконечно много возможностей компилятора, о которых мы еще не думали; мы не реализовали ни одного из них.

Еще одна причина не выдавать здесь предупреждения заключается в том, что мы пытаемся выдавать предупреждения для кода, который , вероятно, будет набран случайно и почти наверняка неправильным по неочевидной причине ]. "this == null" вряд ли будет введено случайно, и хотя это почти наверняка неверно, как вы отметили в формулировке вашего вопроса, это очевидно неверно.

Сравните это с нашим "guid == null" - это может произойти случайно, потому что разработчик может случайно подумать, что Guid является ссылочным типом. Руководства обычно передаются по ссылке в C ++, поэтому легко сделать эту ошибку. Код почти наверняка неверен, но он ошибочен неочевидным образом. Так что это хороший кандидат на предупреждение. (Вот почему так жаль, что это предупреждение в C # 2, но не в C # 3, из-за ошибки, которую мы ввели.)

24
ответ дан 16 October 2019 в 23:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: