0Pricing
C# Academy · レッスン

アノテーション:?、!、MaybeNullとNotNull

nullable型には?、null許容抑制には!を使い、MaybeNullやNotNullWhenなどの属性でフロー解析を正確に行います。

「アノテーション:?、!、MaybeNullとNotNull」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。

? と ! の先へ:Null 許容性アトリビュート

基本的な ? アノテーションと null チェックでほとんどのケースに対応できますが、より表現力の高いアノテーションが必要なパターンもあります。System.Diagnostics.CodeAnalysis 名前空間には、null のフローについてコンパイラーにより深い情報を与えるアトリビュートが用意されています。

MaybeNull と NotNull

[MaybeNull] は、null 非許容の戻り値型でも実際には null を返す可能性があることをコンパイラーに伝えます(ジェネリックメソッドなど)。[NotNull] は、null 許容パラメーターが呼び出し後に null ではなくなることを保証します。

using System.Diagnostics.CodeAnalysis;

// [MaybeNull]: return might be null even though T is non-nullable
[return: MaybeNull]
public T Find<T>(int id)
{
    // Returns default(T) which is null for reference types
    return _cache.TryGetValue(id, out var val) ? val : default!;
}

// [NotNull]: after this call, output is guaranteed non-null
public static void EnsureNotNull<T>(
    [NotNull] ref T? value,
    T defaultValue) where T : class
{
    value ??= defaultValue;
}

NotNullWhen:条件付きの Null 非許容

[NotNullWhen(true)] は、メソッドが true を返した場合に出力パラメーターが null ではないことをコンパイラーに伝えます。標準的な TryParse パターンでは、このようにアノテーションが付けられています。

using System.Diagnostics.CodeAnalysis;

public static bool TryParseEmail(
    string? input,
    [NotNullWhen(true)] out string? email)
{
    if (input?.Contains('@') == true)
    {
        email = input.Trim().ToLower();
        return true;
    }
    email = null;
    return false;
}

// Usage — no warning after true check:
if (TryParseEmail(raw, out var email))
    Console.WriteLine(email.Length); // safe — email is non-null here

MaybeNullWhen:条件付きの Null 許容

[MaybeNullWhen(false)] はその逆で、メソッドが false を返した場合に出力パラメーターが null になる可能性があることを示します。ディクショナリの TryGetValue パターンで使用されます。

// This is how Dictionary<K,V>.TryGetValue is annotated:
public bool TryGetValue(
    TKey key,
    [MaybeNullWhen(false)] out TValue value)
{ ... }

// Usage:
if (!dict.TryGetValue("key", out var value))
    return; // early return — value is null in this branch

Console.WriteLine(value.Length); // safe after the guard

AllowNull と DisallowNull

null 非許容プロパティに [AllowNull] を付けると、呼び出し元が null を渡せるようになります(null を空の文字列に変換する setter など)。[DisallowNull] は、null 許容型に対する null を禁止します。

public class Config
{
    private string _name = "";

    // Allow setting null (setter converts null -> empty)
    [AllowNull]
    public string Name
    {
        get => _name;
        set => _name = value ?? "";
    }

    // Getter always returns non-null: fine
    // Setter accepts null: [AllowNull] tells compiler that's OK
}

NotNullIfNotNull:Null 許容性の伝播

[NotNullIfNotNull(paramName)] は、パラメーター X が null でない場合、戻り値も null ではないことを示します。変換関数に便利です。

[return: NotNullIfNotNull(nameof(value))]
public static string? Normalize(string? value)
{
    return value?.Trim().ToLower();
}

// Usage:
string  name = "  Alice  ";
string  norm1 = Normalize(name)!; // guaranteed non-null
string? raw   = GetRaw();
string? norm2 = Normalize(raw);   // still nullable (raw might be null)

DoesNotReturn

[DoesNotReturn] は、常に例外をスローするメソッドを示します。コンパイラーは、呼び出し後のコードが到達不能であると認識し、不要な null 警告を抑制します。

using System.Diagnostics.CodeAnalysis;

[DoesNotReturn]
public static void ThrowNotFound(int id)
    => throw new KeyNotFoundException($"Entity {id} not found");

// Usage — no null warning after the call:
var order = _db.Orders.Find(id);
if (order is null) ThrowNotFound(id);

Console.WriteLine(order.Id); // no CS8602 — compiler knows ThrowNotFound threw

MemberNotNull:フィールドの事後条件

[MemberNotNull] は、メソッドの戻り後に特定のフィールドが null ではないことを保証することをコンパイラーに伝えます。遅延初期化ヘルパーに便利です。

public class DataLoader
{
    private string? _data;

    [MemberNotNull(nameof(_data))]
    private void EnsureLoaded()
    {
        if (_data is null)
            _data = LoadFromFile();
    }

    public string GetData()
    {
        EnsureLoaded();
        return _data; // no CS8603 — compiler knows _data is set
    }
}

アノテーションの組み合わせ

アトリビュートを組み合わせることで、API の契約を正確に表現できます。ここでは、複数のアトリビュートを組み合わせた fluent なガードヘルパーを示します。

public static class Guard
{
    [return: NotNull]
    public static T NotNull<T>(
        [NotNull][AllowNull] T? value,
        [CallerArgumentExpression(nameof(value))] string? name = null)
        where T : class
    {
        ArgumentNullException.ThrowIfNull(value, name);
        return value;
    }
}

// Usage:
var product = Guard.NotNull(await _repo.FindAsync(id));
Console.WriteLine(product.Name); // no warning

Null 演算子:?. ?? ??=

null 条件演算子(?.)、null 合体演算子(??)、null 合体代入演算子(??=)を使うと、冗長な if チェックなしで簡潔な null 安全コードを記述できます。

string? name = GetName();

// ?. safe navigation
int? len = name?.Length;
string? upper = name?.ToUpper().Trim();

// ?? default value
string display = name ?? "Anonymous";

// ??= lazy init
name ??= "Default";

// Chaining
string result = user?.Profile?.DisplayName ?? user?.Name ?? "Guest";

クイックチェック

out パラメーターに付けた [NotNullWhen(true)] は、コンパイラーに何を伝えますか。

まとめ:Null 許容性アノテーション

重要なポイント:

  • [NotNullWhen(true)]:TryParse パターン。true を返した場合は null ではない
  • [MaybeNull]:null 非許容型でも null を返す可能性がある(ジェネリックの既定値など)
  • [DoesNotReturn]:メソッドは常に例外をスローするため、その後のコードには到達しない
  • [MemberNotNull]:メソッドの戻り後にフィールドが設定済みであることを保証する
  • ?.、??、??=:簡潔な null 安全ナビゲーションと既定値の指定

よくある質問

「アノテーション:?、!、MaybeNullとNotNull」レッスンは無料ですか?

はい。「アノテーション:?、!、MaybeNullとNotNull」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。

「アノテーション:?、!、MaybeNullとNotNull」で何を学びますか?

nullable型には?、null許容抑制には!を使い、MaybeNullやNotNullWhenなどの属性でフロー解析を正確に行います。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C# Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「アノテーション:?、!、MaybeNullとNotNull」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC# Academyレッスンでコードを書いて実行できますか?

はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. NRTの有効化と理解
  2. アノテーション:?、!、MaybeNullとNotNull
  3. Null条件演算子とNull合体演算子
  4. コードベースのNRTへの移行
← C# Academyに戻る