Checking type parameter of a generic method in C#

C#GenericsTypechecking

C# Problem Overview


Is it possible to do something like this in 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
        ...
    }
}

C# Solutions


Solution 1 - C#

Yes:

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

It's slightly odd that you need to go via a cast to object, but that's just the way that generics work - there aren't as many conversions from a generic type as you might expect.

Of course another alternative is to use the normal execution time check:

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

That will behave differently to the first code block if t is null, of course.

I would try to avoid this kind of code where possible, however - it can be necessary sometimes, but the idea of generic methods is to be able to write generic code which works the same way for any type.

Solution 2 - C#

Starting with C# 7, you can do this in a concise way with the is operator:

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

See documentation: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/is#pattern-matching-with-is

Solution 3 - C#

It's 2017 and we have now C# 7 with pattern matching. If your type T inherit object you can you code like this

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;}
}

Solution 4 - C#

I believe there's something wrong in your design. You want to compare between types in an already generic method. Generics are meant to deal with type-variable situation. I recommend to do it this way..

//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>
{
    ...
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsynergeticView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#mark.monteiroView Answer on Stackoverflow
Solution 3 - C#SousukeView Answer on Stackoverflow
Solution 4 - C#this. __curious_geekView Answer on Stackoverflow