【C#】implicit / explicitキーワードで型変換演算子を定義する

C#でimplicit / explicitキーワードを使って型変換演算子を定義する方法についてまとめました。

型変換を定義?

C#では通常(型変換を定義しない場合)、継承関係に無い型同士はキャストできません。

public class Foo{}
public class Bar{}

var foo = new Foo();
var bar = (Bar) foo; // 出来ない

ここでimplicitやexplicitなどのキーワードを使って型変換を定義すると、親子関係に無い型にキャストできるようになります。

public class Foo{}
public class Bar{}

var foo = new Foo();
Bar bar = (Bar) foo; // 出来るようになる

やりかた

以下のようにimplicitキーワードとoperatorキーワードを組み合わせてstaticな変換メソッドを定義することで、暗黙的なキャストが可能になります。

public class Foo
{
    public static implicit operator Bar(Foo self)
    {
        // FooからBarを生成して返す
        return new Bar();
    }
}

public class Bar{}

var foo = new Foo();
Bar bar = foo; // 暗黙的なキャスト

またimplicitではなくexplicitを使うと、明示的なキャストのみができるようになります。

public class Foo
{
    public static explicit operator Bar(Foo self)
    {
        // FooからBarを生成して返す
        return new Bar();
    }
}

public class Bar{}

var foo = new Foo();
Bar bar = (Bar)foo; // 明示的なキャスト

組み込み型へのキャスト

型変換演算子の主な使いどころとして、組み込み型へのキャストが挙げられます。
以下はstringを値として保持するId型の構造体をstringにキャストできるようにする例です。

public struct Id
{
    public Id(string value)
    {
        Value = value;
    }

    public string Value { get; }

    public static explicit operator string(Id self)
    {
        return self.Value;
    }
}

自作型へのキャスト

使いどころは難しいですが(というか変に使うとカオスになりますが)、自作型へのキャストもできます。
以下では、getter/setterを持つモデルFooからgetterのみを持つ読み込み専用モデルにキャストできるようにしています。

public class Foo
{
    public string Name { get; set; }

    public static implicit operator ReadOnlyFoo(Foo self)
    {
        return new ReadOnlyFoo(self);
    }
}

public class ReadOnlyFoo
{
    private Foo _source;
    
    public ReadOnlyFoo(Foo source)
    {
        _source = source;
    }

    public string Name => _source.Name;
}

参考

docs.microsoft.com