web-dev-qa-db-ja.com

C#でジェネリックメソッドの型パラメーターを確認する

C#でこのようなことをすることは可能ですか?

public void DoSomething<T>(T t)  
{
    if (T is MyClass)
    {
        MyClass mc = (MyClass)t 
        ...
    }
    else if (T is List<MyClass>)
    {
        List<MyClass> lmc = (List<MyClass>)t
        ...
    }
}
53
synergetic

はい:

if (typeof(T) == typeof(MyClass))
{
    MyClass mc = (MyClass)(object) t;
}
else if (typeof(T) == typeof(List<MyClass>))
{
    List<MyClass> lmc = (List<MyClass>)(object) t;
}

オブジェクトへのキャストを経由する必要があるのは少し奇妙ですが、それはジェネリックが機能する方法です-ジェネリック型からの変換は期待したほど多くありません。

もちろん、別の代替方法は、通常の実行時間チェックを使用することです。

MyClass mc = t as MyClass;
if (mc != null)
{
    // ...
}
else
{
    List<MyClass> lmc = t as List<MyClass>;
    if (lmc != null)
    {
        // ...
    }
}

もちろん、tがnullの場合、最初のコードブロックとは異なる動作をします。

私はtryこの種のコードを可能な限り回避したいと思います-しかし、それは時々必要になることがありますが、ジェネリックメソッドのアイデアはgeneric動作するコードを書くことができることですどのタイプでも同じです。

92
Jon Skeet

2017年で、パターンマッチングを備えたC#7ができました。タイプTがobjectを継承する場合、次のようにコーディングできます

void Main()
{
    DoSomething(new MyClass { a = 5 });
    DoSomething(new List<MyClass> { new MyClass { a = 5 }, new MyClass { a = 5 }});
}


public void DoSomething(object t)
{
    switch (t)
    {
        case MyClass c:
            Console.WriteLine($"class.a = {c.a}");
            break;
        case List<MyClass> l:
            Console.WriteLine($"list.count = {l.Count}");
            break;
    }
}

class MyClass
{
    public int a { get; set;}
}
8
Sousuke

C#7以降では、is演算子を使用してこれを簡潔に行うことができます。

public void DoSomething<T>(T value)  
{
    if (value is MyClass mc)
    {
        ...
    }
    else if (value is List<MyClass> lmc)
    {
        ...
    }
}

ドキュメントを参照してください: https://docs.Microsoft.com/en-us/dotnet/csharp/language-reference/keywords/is#pattern-matching-with-is

5
mark.monteiro

デザインに何か問題があると思います。 すでにジェネリックなメソッドで型を比較したい。ジェネリックは型変数の状況に対処することを意図している。このようにすることをお勧めする。

//Generic Overload 1
public void DoSomething<T>(T t)
    where T : MyClass
{
    ...
}

//Generic Overload 2
public void DoSomething<T>(T t)
    where T : List<MyClass>
{
    ...
}