Help us understand the problem. What is going on with this article?

C# ジェネリック(ジェネリクス)

ジェネリック(ジェネリクス)

様々な型に対応する関数(やクラス)を定義することができます。

例えば、以下の様な関数があったとします。

Int32 score = 5;
Int32 old_score = 3;

public static Int32 GetHighestScore()
{
    return (score > old_score) ? score : old_score;
}

万が一、scoreold_scoredoublefloatであった場合、
以下の様に別で関数定義する必要があります。

public static Int32 GetHighestScore()
{
    return (score > old_score) ? score : old_score;
}

double score = 5;
double old_score = 3;

public static double GetHighestScoreA()
{
    return (score > old_score) ? score : old_score;
}

といったように、複数のパターンを想定した関数を定義することで解決します。
しかしながら、これは悪い例です。
ハードコーディングですし、プログラムのメンテナンス性(保守性)も最悪です。
これを解決してくれるのが、ジェネリックです。

今回の場合、以下の様に関数定義を行います。

static Int32 score = 5;
static Int32 old_score = 3;

public static unsafe T GetHighestScore<T>(T one, T two) where T : unmanaged, IComparable
{
    if(one.CompareTo(two) > 0)
    {
        return one;
    }
    return two;
}

ここでいう、where T : unmanagedは、型がアンマネージド型であることを条件にするという意味です。

アンマネージド型とは

sbyte byteshortintuintlong
ulongcharfloatdoubledecimalbool
がアンマネージド型です。
アンマネージド型 (C# リファレンス)

実例

実例として、MarshalStructureToPtrをメソッドとして簡易化してみます。
(※Marshal.StructureToPtr()もジェネリック型として定義されていますね!)

public struct myStruct
{
    public int x;
    public int y;
}

static void Main(string[] args)
{
    Console.Title = "ジェネリック";

    myStruct ms = new myStruct();
    var pStructure = StructureToPointer<myStruct>(ms);
    Console.WriteLine("構造体ポインタ: " + (Int32)(pStructure));

    Console.ReadKey();
}

////////////////////////////////////////////////////////////////////////
// 構造体のマーシャリング
////////////////////////////////////////////////////////////////////////
public unsafe static IntPtr StructureToPointer<T>(T 構造体) where T : struct
{
    var size = Marshal.SizeOf(構造体.GetType());
    IntPtr pStructure = Marshal.AllocCoTaskMem(size); //アンマネージドメモリの確保
    Marshal.StructureToPtr(構造体, pStructure, false); //確保した領域に構造体ポインタを展開
    Marshal.DestroyStructure(pStructure, typeof(T));//後処理
    Marshal.FreeCoTaskMem(pStructure);//確保したアンマネージドメモリの解放
    return pStructure;
}

構造体から構造体ポインタへのマーシャリングを簡易化する関数です。
ここでは、where T : structとし、型がstructであることを条件とします。

本来、マネージド型である(アンマネージド型ではない)ジェネリック関数ではsizeof()を使用することができません。(sizeof()がアンマネージド型にのみ対応している為)
なので、Marshal.Sizeof()を使用します。

実行結果:
e94d408e6c8952113f74b4c19bdb3cb7.png

kkent030315
もうすぐ高校1年生です。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした