Подтвердить что ты не робот

С# 6.0 Null Propagation Operator & Assignment

Этот вопрос был полностью пересмотрен в интересах тщательного объяснения.

Я заметил, что, по-видимому, довольно плохое ограничение оператора распространения NULL в С# 6.0 тем, что вы не можете вызвать свойство seters для объекта, который был распространен в NULL (хотя вы можете вызвать свойство getters против объекта, который был передан в ноль). Как вы увидите из сгенерированного ИЛ (который я отразил на С#), нет ничего, что должно было бы ограничить возможность вызова средств определения свойств с использованием нулевого распространения.

Для начала я создал простой класс с использованием методов Get/Set в стиле Java и свойства с открытым доступом к getter/setter.

public class Person
{
    public Person(string name, DateTime birthday)
    {
        Name = name;
    }

    public string Name { get; set; }

    public void SetName(string name)
    {
        Name = name;
    }

    public string GetName()
    {
        return Name;
    }
}

Я тестировал способность нулевого распространения в следующем тестовом классе.

public class Program
{
    public static void Main(string[] args)
    {
        Person person = new Person("Joe Bloggs", DateTime.Parse("01/01/1991"));

        // This line doesn't work - see documented error below
        person?.Name = "John Smith";

        person?.SetName("John Smith");

        string name = person?.Name;
    }
}

Левая часть присваивания должна быть переменной, свойством или индексатор.

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

Посмотрим на С#, который был сгенерирован из этого кода:

public static void Main(string[] args)
{
    Person person = new Person("Joe Bloggs", DateTime.Parse("01/01/1991"));
    if (person != null)
    {
        person.SetName("John Smith");
    }
    string arg_33_0 = (person != null) ? person.Name : null;
}

Обратите внимание, что при использовании против метода SetName преобразование в null преобразуется в простой оператор if и что при использовании против getter Name свойство тернарного оператора используется либо для получения значения Name или null.

Одна вещь, которую я заметил здесь, - это разница в поведении между использованием оператора if и использованием тернарного оператора: при использовании setter использование оператора if будет работать, тогда как использование тернарного оператора не будет.

public static void Main(string[] args)
{
    Person person = null;

    if (person != null)
    {
        person.Name = "John Smith";
    }

    person.Name = (person != null) ? "John Smith" : null;
}

В этом примере я использую как оператор if, так и тернарный оператор, чтобы проверить, является ли человек null, прежде чем пытаться назначить его свойство Name. оператор if работает, как ожидалось; утверждение, использующее тернарный оператор, терпит неудачу, как ожидалось

Ссылка на объект не установлена ​​в экземпляр объекта.

На мой взгляд, ограничение связано с возможностью С# 6.0 преобразовывать нулевое распространение в оператор if или тройное выражение. Если бы он был разработан для использования только операторов if, присвоение свойств работало бы с помощью пустого распространения.

До сих пор я не видел одного убедительного аргумента относительно того, почему это НЕ ДОЛЖНО быть возможным, поэтому я все еще ищу ответы!

4b9b3361

Ответ 1

Ты не единственный! SLaks поднял это как проблему (теперь здесь)

Почему я не могу написать такой код?

Process.GetProcessById(2)?.Exited += delegate { };

и после того, как это было кратко закрыто как "По замыслу"

? Оператор никогда не выдает lvalue, так что это сделано специально.

кто-то сказал, что это было бы хорошо для установщиков свойств, а также обработчиков событий

Может быть, добавить также свойства сеттеров в запрос, как:

Object?.Prop = false;

и он был вновь открыт как запрос функции для С# 7.

Ответ 2

Вы не можете использовать оператор NULL-распространения таким образом.

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

Вам нужно придерживаться простой старой проверки:

if (a != null)
{
    a.Value = someValue;
}

Ответ 3

Попробуй вот так...

using System;

namespace TestCon
{
    class Program
    {
        public static void Main()
    {

        Person person = null;
        //Person person = new Person() { Name = "Jack" };

        //Using an "if" null check.
        if (person != null)
        {
            Console.WriteLine(person.Name);
            person.Name = "Jane";
            Console.WriteLine(person.Name);
        }

        //using a ternary null check.
        string arg = (person != null) ? person.Name = "John" : arg = null;
        //Remember the first statment after the "?" is what happens when true. False after the ":". (Just saying "john" is not enough)
        //Console.WriteLine(person.Name);

        if (arg == null)
        {
            Console.WriteLine("arg is null");
        }

        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
public class Person
{
    public string Name { get; set; }
}

}