Невозможно преобразовать ноль в структуру при определении двух неявных неявных операторов - PullRequest
0 голосов
/ 20 сентября 2018

Следующее не компилируется:

public struct Foo
{
    public static implicit operator Foo(string bar)
    {
        return new Foo();
    }

    public static implicit operator Foo(long? bar)
    {
        return new Foo();
    }

    public static void Test()
    {
        Foo bar = 0;
        Foo bar2 = (long?)null;
        Foo bar3 = "";
        Foo bar4 = null; // Cannot convert null to 'Foo' because it is a non-nullable value type
    }
}

'Foo bar4 = null' завершается неудачей, предположительно потому, что компилятор не знает, какой неявный оператор использовать, потому что смена оператора на long?long приводит к компиляции этой строки, но вместо этого «Foo bar2 = (long?) null» завершается с ошибкой (требуется явное приведение).

Мой вопрос таков;Есть ли способ заставить 'Foo bar4 = null' работать, или это просто ограничение языка (я не могу добавить оператор 'null' или сказать ему, какой использовать, например, для null)?

Я понимаю, что могу изменить структуру на класс, но я не хочу, чтобы она была нулевой, я хочу иметь возможность создавать экземпляр NULL.

РЕДАКТИРОВАТЬ: Я должен добавить, что я понимаю, что есть много способов обойти это, но так как '= null' (выполнение 'new Foo ()' по существу) работает только с одним из неявных операторов, я простоИнтересно, возможно ли, чтобы это все еще работало с ними обоими (я чувствую, что на языке должен быть способ сделать это - сейчас или в будущем, нет?).

Ответы [ 3 ]

0 голосов
/ 20 сентября 2018

Если я не ошибаюсь, структуре никогда не может быть присвоено значение null, потому что это тип значения, подобный int, bool и DateTime.

. Вы можетеоднако используйте Nullable примерно так:Foo? bar4 = null;или жеNullable<Foo> bar4 = null;

Убедитесь, что вы относитесь к нему как к любому другому Nullable и проверяете .HasValue перед ссылкой bar4.Value, чтобы избежать чудесного исключения NullReferenceException.

0 голосов
/ 20 сентября 2018

Мой вопрос;Есть ли способ заставить 'Foo bar4 = null' работать, или это просто ограничение языка (я не могу добавить оператор 'null' или сказать ему, какой использовать, например, для null)?

Основываясь на этом вопросе и ваших изменениях, вы в основном спрашиваете

Почему Foo bar4 = null компилируется, если нет, если я добавляю еще один неявный оператор приведения?

Ответ прост.null без какого-либо контекста не содержит типов, поэтому компилятор не знает, какой оператор использовать.Зачем?Хорошо, алгоритм разрешения перегрузки, лежащий в основе языка, не проверяет тип того, что вы пытаетесь присвоить null, поэтому он не знает, какой оператор вы намеревались.

Вы можете утверждать, что будущий языкСпецификация может быть изменена для выполнения этого дополнительного анализа, но команда, вероятно, считает, что это не стоит усилий, или это будет серьезное изменение.

Лучшее, что вы можете сделать, - это избежать кастинга в этом случае.Вы можете, в зависимости от вашего уровня C #, выполнить одно из следующих действий:

  • Foo bar4 = default;
  • Foo bar4 = default(Foo);

, в результате чего можно использовать Foo.Два выражения по умолчанию и new Foo() все эквивалентны.Все они приводят к структуре со всеми обнуляемыми полями.

Для получения дополнительной информации вы можете увидеть выражения значений по умолчанию в руководстве по программированию на C #.

И, наконец,в то время как вы можете обойтись без единого неявного оператора приведения, который преобразует null в структуру, это не означает, что вы должны .Кто-то, читающий этот код, не знающий об актерах, вероятно, подвергнет сомнению их здравомыслие в течение нескольких минут.Лучше не уходить от идиоматического кода, если можете.

0 голосов
/ 20 сентября 2018

Ваша структура не обнуляется, потому что вы вводите приведение, которое позволяет приводить нулевое значение к этому типу.Сам по себе актерский состав - это просто член, который не меняет типы семантика .

На самом деле struct сам по себе никогда нулевой, однако ссылки на может быть, но только если они относятся к типу Nullable<Foo>.Поэтому bar4 должен иметь тип Foo?, который совпадает с Nullable<Foo>.

...