C#で要素数が最大1個のコレクション「OnlyOneCollection」を作りNull許容型変数を置き換えてみる。

C# コンピュータ
C#

IEnumerableの実装に挑戦してみたいと思います。

こちらのクラスはOnlyOneCollectionとコレクションを銘打ってはいますが、実際は要素数が0または1つのみ格納できるコンテナクラスとなっております。使い道としてはNull許容の変数をの代わりに、nullの場合要素数が0のOnlyOneCollection>T<.None()を生成し、要素がある場合OnlyOneCollection>T<.One(T value);を生成ます。内部の要素は基本的にforeachか、ToList()で変換してLINQで取り出して使うことになります。そうすることでnullチェックを省くことが出来ます。

ソースコード

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;

using System.Linq;

public class OnlyOneCollection<T> : IEnumerable<T>
{
    T? _value;
    OnlyOneCollection()
    {

    }
    OnlyOneCollection(T value)
    {
        _value = value;
    }
    public static OnlyOneCollection<T> One(T value)
    {
        return new OnlyOneCollection<T>(value);
    }
    public static OnlyOneCollection<T> None()
    {
        return new OnlyOneCollection<T>();
    }
    public T Value
    {
        set
        {
            _value = value;
        }
    }
    public IEnumerator<T> GetEnumerator()
    {
        if (_value is not null)
        {
            yield return _value;
        }
        else
        {
            yield break;
        }
    }
    IEnumerator IEnumerable.GetEnumerator() => (IEnumerator) GetEnumerator();
    public void Clear()
    {
        _value = default;
    }
    public List<T> ToList()
    {
        if (_value is not null)
        {
            return new List<T> { _value };
        }
        else
        {
            return new List<T>();
        }
    }
}
public class Program
{
    public static void Main()
    {
        var vars = OnlyOneCollection<string>.None();
        foreach(var v in vars)
        {
            // 実行されない
            Console.WriteLine(v);
        }

        vars = OnlyOneCollection<string>.One("A");
        foreach(var v in vars)
        {
            // 実行される
            Console.WriteLine(v);
            // 結果
            // A
        }
        vars.Value = "B";
        vars.ToList().ForEach(e =>
        {
            // 実行される
            Console.WriteLine(e);
            // 結果
            // B
        });
        vars.Clear();
        foreach(var v in vars)
        {
            // 実行されない
            Console.WriteLine(v);
        }
    }
}

思い付きで作成しましたが、foreachが出来ましたので、IEnumerable<T>の実装として動いているようです。

コメント