3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C# .NET10 Preview3】null 条件付き代入

Posted at

はじめに

.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 は他にいくつか面白い追加機能があるため、追って取り上げようと思います。

.NET10 Preview3

関連
【C#】.NET 10 Preview 1 キタ━━(゚∀゚)━━!!
【C# .NET 10 Preview 1】値型の配列をスタックに作成する最適化の検証
【C# .NET 10 Preview 2】参照型がスタックに置かれる最適化

3
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?