はじめに
.NET10 Preview3 が利用可能になりました。
月1更新だと思うのですが、なんか毎回1週間前倒しになってるような・・・
リリースノートによれば色々と機能追加されています。
今回はそのうちの C# 機能のひとつ null
条件付き代入を見ていきます。
サンプルコード
サンプルコード
using System.Linq.Expressions;
using Xunit;
file class Customer
{
public string Name { get; set; } = "John";
public int Age { get; set; } = 20;
}
public class __NullConditionalAssignmentTest
{
[Fact]
void HowToUse()
{
var customer = new Customer();
customer?.Name = "Bob";
customer?.Age = 30;
Assert.Equal("Bob", customer!.Name);
Assert.Equal(30, customer!.Age);
Customer? nullCustomer = null;
nullCustomer?.Name = "Alice"; // 何もしない
nullCustomer?.Age = 25; // 何もしない
Assert.Null(nullCustomer?.Name);
Assert.Null(nullCustomer?.Age);
// 従来の書き方
if (nullCustomer is not null)
{
nullCustomer.Name = "Charlie";
nullCustomer.Age = 35;
}
}
#if false
void Exp()
{
// 式ツリーのラムダに null 伝搬演算子を含めることはできません。CS8072
// 式ツリーは、代入演算子を含むことはできませんCS0832
Expression<Action<Customer?, string>> setNameExpression =
(customer, name) => customer?.Name = name;
}
#endif
}
null
条件付き代入
file class Customer
{
public string Name { get; set; } = "John";
public int Age { get; set; } = 20;
}
var customer = new Customer();
customer?.Name = "Bob";
customer?.Age = 30;
Assert.Equal("Bob", customer!.Name);
Assert.Equal(30, customer!.Age);
Customer? nullCustomer = null;
nullCustomer?.Name = "Alice"; // 何もしない
nullCustomer?.Age = 25; // 何もしない
Assert.Null(nullCustomer?.Name);
Assert.Null(nullCustomer?.Age);
// 従来の書き方
if (nullCustomer is not null)
{
nullCustomer.Name = "Charlie";
nullCustomer.Age = 35;
}
これまでは obj?.Value = 1
みたいなのはコンパイルエラーになっていたのですが、代入できるようになりました。用途は割と限定的ですが、nullable
の登場で需要があったんだと思います。
式木には使えない
// 式ツリーのラムダに null 伝搬演算子を含めることはできません。CS8072
// 式ツリーは、代入演算子を含むことはできませんCS0832
Expression<Action<Customer?, string>> setNameExpression = (customer, name) =>
customer?.Name = name;
式木には使えません。これがなぜか考えてみると、null
許容演算子は糖衣構文で1行の式ではなさそうです。
上の使用例を逆コンパイルしてみます。
<コンパイラによる名前>__Customer customer = new <コンパイラによる名前>__Customer();
if (customer != null)
{
customer.Name = "Bob";
}
if (customer != null)
{
customer.Age = 30;
}
Assert.Equal("Bob", customer.Name);
Assert.Equal<int>(30, customer.Age);
<コンパイラによる名前>__Customer nullCustomer = null;
// if 文に置き換わっている!
if (nullCustomer != null)
{
nullCustomer.Name = "Alice";
}
// if 文に置き換わっている!
if (nullCustomer != null)
{
nullCustomer.Age = 25;
}
Assert.Null((nullCustomer != null) ? nullCustomer.Name : null);
Assert.Null<int>((nullCustomer != null) ? new int?(nullCustomer.Age) : null);
bool flag = nullCustomer != null;
if (flag)
{
nullCustomer.Name = "Charlie";
nullCustomer.Age = 35;
}
コンパイル結果は if
文による複数行のコードになるため、これは式木には使えません。式木関係は複雑な機能なので、基本的に式木には機能追加しない方針なのでしょう。
おわりに
今回取り上げた追加機能はかゆところに手が届く系のものでした。
Preview3 は他にいくつか面白い追加機能があるため、追って取り上げようと思います。
関連
【C#】.NET 10 Preview 1 キタ━━(゚∀゚)━━!!
【C# .NET 10 Preview 1】値型の配列をスタックに作成する最適化の検証
【C# .NET 10 Preview 2】参照型がスタックに置かれる最適化