C#のコードで、変数名の後ろに!記号がある場合の意味を紹介します。
#TOC(caption="目次")
!
記号はnull免除演算子(null-forgiving operator)と呼ばれます。!
をnull許容参照型の変数名の後ろに記述すると、その変数は null でないとみなされます。下図のフォームを作成します。
下記コードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace NullForgivingDemo
{
public partial class FormSimpleNullForgiving : Form
{
public FormSimpleNullForgiving()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string str = "ぺんぎんクッキー";
string? newstr = "かるがもタルト";
if (new Random().NextDouble() < 0.5) newstr = default;
str = newstr;
textBox1.Text = str;
}
}
}
ビルドを実行すると、下記のワーニングが発生します。
string?
型のdefault値はnullとなるため、string型にnullを代入してしまう場合があります。このため、コンパイル時に先のワーニングが発生します。
string? newstr = "かるがもタルト";
if (new Random().NextDouble() < 0.5) newstr = default;
str = newstr;
以下のコードに修正すると、ワーニングが発生しなくなります。
private void button1_Click(object sender, EventArgs e)
{
string str = "ぺんぎんクッキー";
string? newstr = "かるがもタルト";
if (new Random().NextDouble() < 0.5) newstr = default;
str = newstr!;
textBox1.Text = str;
}
newstr!
の記述により、newstr変数はnullでないとみなされます。そのため、ワーニングは発生しなくなります。
一方で実行時の動作は変わらないため、元のコードと動作は全く同じになります。
str = newstr!;
プロジェクトをビルドすると、上記のアラートは発生しないことが確認できます。
プロジェクトを実行します。下図のウィンドウが表示されます。
[button1]をクリックします。下部のテキストボックスに「かるがもタルト」の文字列が表示されるか、テキストボックスが空白になるかの動作をします。
乱数による動作のため、クリックするごとにどちらかの表示になります。
なお、nullが代入される状況が発生しない下記のコードではワーニングは発生しません。
private void button2_Click(object sender, EventArgs e)
{
string str = "ぺんぎんクッキー";
string? newstr = "かるがもタルト";
str = newstr;
textBox1.Text = str;
}
!
を記述してもビルドエラーになります。 private void button3_Click(object sender, EventArgs e)
{
int value = 100;
int? newvalue = 56;
if (new Random().NextDouble() < 0.5) newvalue = null;
value = newvalue!;
textBox1.Text = value.ToString();
}
次のエラーが発生します。
次のプログラムを作成します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace NullForgivingDemo
{
public partial class FormSimpleNullForgiving : Form
{
class MyItem
{
public int id = -1;
public string name = "ぺんぎんクッキー";
}
public FormSimpleNullForgiving()
{
InitializeComponent();
}
private void button4_Click(object sender, EventArgs e)
{
MyItem? item = null;
textBox1.Text = String.Format("名前 : {0}", item.name);
}
}
}
ビルドを実行すると、下記のワーニングが発生します。
MyItem?
型のitem変数はnullとなるため、item.nameは NullPointerExceptionとなり、コンパイル時に先のワーニングが発生します。 MyItem? item = null;
textBox1.Text = String.Format("名前 : {0}", item.name);
以下のコードに修正すると、ワーニングが発生しなくなります。
private void button4_Click(object sender, EventArgs e)
{
MyItem? item = null;
textBox1.Text = String.Format("名前 : {0}", item!.name);
}
プロジェクトをビルドして実行し、button4をクリックします。nullのメンバ変数にアクセスしたため、例外が発生します。
下記例外が発生します。
!
null 免除演算子を記述してもワーニングの発生を抑えられるだけで、nullのオブジェクトにアクセスしたことによる例外は回避できません。