C# 6.0 Нулевой оператор распространения и присвоение свойства
Этот вопрос был полностью пересмотрен в интересах подробного объяснения.
Я заметил то, что кажется довольно слабым ограничением оператора распространения нулей в C# 6.0 в том, что вы не можете вызывать установщики свойств для объекта, который был передан нулевым значением (хотя вы можете вызывать методы получения свойств для объекта, который был передан нулевым), Как вы увидите из сгенерированного IL (который я отразил в C#), нет ничего, что могло бы ограничить возможность вызова установщиков свойств с использованием нулевого распространения.
Для начала я создал простой класс с методами Get/Set в стиле Java и свойством с общедоступным доступом для получения / установки.
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(...)
работает, и вы также можете заметить, что получение значения свойства с нулевым распространением также работает.
Давайте посмотрим на C#, который был сгенерирован из этого кода:
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
метод, нулевое распространение превращается в простой if
заявление, и что при использовании против Name
для получения свойства, троичный оператор используется либо для получения значения Name
или же null
,
Одна вещь, которую я заметил здесь, это разница в поведении между использованием if
оператор и использование троичного оператора: при использовании сеттера, используя 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
выписка работает как положено; оператор с использованием тернарного оператора завершается неудачно, как и ожидалось
В экземпляре объекта не задана ссылка на объект.
На мой взгляд, ограничение исходит из способности C# 6.0 преобразовывать нулевое распространение в if
утверждение или троичное выражение. Если бы он был предназначен для использования только if
заявления, присваивание свойства будет работать через нулевое распространение.
До сих пор я не видел ни одного убедительного аргумента о том, почему это НЕ ДОЛЖНО быть возможным, поэтому я все еще ищу ответы!
3 ответа
Ты не единственный! SLaks поднял это как проблему
Почему я не могу написать такой код?
Process.GetProcessById(2)?.Exited += delegate { };
и после того, как это было кратко закрыто как "По замыслу"
? Оператор никогда не выдает lvalue, так что это по замыслу.
кто-то сказал, что это было бы хорошо для установщиков свойств, а также обработчиков событий
Может быть, добавить также параметры настройки в запрос, как:
Object?.Prop = false;
и он был вновь открыт как запрос функции для C#7.
Вы не можете использовать оператор нулевого распространения таким образом.
Этот оператор позволяет распространять нули при оценке выражения. Он не может использоваться в качестве цели назначения точно так, как предполагает ошибка.
Вы должны придерживаться простой старой проверки нуля:
if (a != null)
{
a.Value = someValue;
}
Попробуйте это так...
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; }
}
}