滅入るんるん

何か書きます

Kotlin使いのためのC#入門 Generics

> Top

C#もKotlinと同様にジェネリクスが存在しますが、Kotlin/Javaよりも高性能なジェネリクスが搭載されています。Kotlinでは型パラメーターの情報は実行時には削除されますが、C#では型パラメーターの情報を保持しているため、Kotlinのジェネリクスにはできないことができます。 たとえば、型パラメーターの型へのキャストなど。 また、構造体にも対応しているため、Javaのようにboxingする必要がありません。

基本的にはKotlinと同様な記法になっています。

class Value<T>
{
    public Value(T value)
    {

    }
}

class User
{
    public void Main()
    {
        var value = new Value<string>(string.Empty);
    }
}

Variance

C#のジェネリクスには共変性と反変性があります。

共変性は型パラメーターにout修飾子を付けることで宣言します。out修飾子を付けた型パラメーターは出力(返り値など)にしか使えなくなります。

interface IValue<out T>
{
    T Main();
}

class Value<T> : IValue<T>
{
    public T Main()
    {
        // 参照型の場合はnull、値型の場合は既定値を返す特別なキーワード
        return default;
    }
}

class User
{
    public void Main()
    {
        IValue<string> stringValue = new Value<string>();
        // 共変性があるので型パラメーターのアップキャストができる
        IValue<object> objectValue = stringValue;
    }
}

反変性は型パラメーターにin修飾子を付けることで宣言します。in修飾子を付けた型パラメーターは入力(引数など)の型にしか使えなくなります。

interface IValue<in T>
{
    void Main(T value);
}

class Value<T> : IValue<T>
{
    public void Main(T value)
    {

    }
}

class User
{
    public void Main()
    {
        IValue<object> objectValue = new Value<object>();
        // 反変性があるので型パラメーターのダウンキャストができる
        IValue<string> stringValue = objectValue;
    }
}

また、型パラメーターにはwhereによってconstraint(制約)を付けることができます。

たとえば、型パラメーターに対して基底型の制約を付ける付けることができます。

interface IStatus
{

}

interface IUser<TStatus> where TStatus : IStatus
{

}

また、Kotlin/JavaにはなくてC#にはある制約の強みとして、引数0のコンストラクターが存在する制約も付けることができます。

interface IStatus
{

}

interface IUser<TStatus> where TStatus : IStatus, new()
{

}

これ以外にも構造体などの制約を加えることができますが、詳しくはドキュメントを参照してください。

interface IValue<T> where T : struct { }

Declaration-site variance

説明済みのような気がするので割愛。

Type projections

おそらくC#にはない機能のことを説明してるので割愛。

というか、共変性と反変性が該当する機能かも。

Generic functions

C#にもジェネリクスメソッドがあります。 機能はあまり変わらないので説明略。

class Value
{
    public void Sub<T>(T value) { }

    public void Main()
    {
        Sub<string>(string.Empty);

        // 引数から型パラメーターを型推論できる
        Sub(string.Empty);
    }
}

Generic constraints

説明済みなので割愛。

Type erasure

Kotlin特有の型チェックなので割愛。