Value of type 'T' cannot be converted to

C#.NetGenericsCasting

C# Problem Overview


This is likely a a novice question, but google surprisingly did not provide an answer.

I have this rather artificial method

T HowToCast<T>(T t)
{
    if (typeof(T) == typeof(string))
    {
        T newT1 = "some text";
        T newT2 = (string)t;
    }

    return t;
}

Coming from a C++ background I have expected this to work. However, it fails to compile with "Cannot implicitly convert type 'T' to string" and "Cannot convert type 'T' to string" for both of the above assignments.

I am either doing something conceptually wrong or just have the wrong syntax. Please help me sort this one out.

Thank you!

C# Solutions


Solution 1 - C#

Even though it's inside of an if block, the compiler doesn't know that T is string.
Therefore, it doesn't let you cast. (For the same reason that you cannot cast DateTime to string)

You need to cast to object, (which any T can cast to), and from there to string (since object can be cast to string).
For example:

T newT1 = (T)(object)"some text";
string newT2 = (string)(object)t;

Solution 2 - C#

Both lines have the same problem

T newT1 = "some text";
T newT2 = (string)t;

The compiler doesn't know that T is a string and so has no way of knowing how to assign that. But since you checked you can just force it with

T newT1 = "some text" as T;
T newT2 = t; 

you don't need to cast the t since it's already a string, also need to add the constraint

where T : class

Solution 3 - C#

I know similar code that the OP posted in this question from generic parsers. From a performance perspective, you should use Unsafe.As<TFrom, TResult>(ref TFrom source), which can be found in the System.Runtime.CompilerServices.Unsafe NuGet package. It avoids boxing for value types in these scenarios. I also think that Unsafe.As results in less machine code produced by the JIT than casting twice (using (TResult) (object) actualString), but I haven't checked that out.

public TResult ParseSomething<TResult>(ParseContext context)
{
    if (typeof(TResult) == typeof(string))
    {
        var token = context.ParseNextToken();
        string parsedString = token.ParseToDotnetString();
        return Unsafe.As<string, TResult>(ref parsedString);
    }
    else if (typeof(TResult) == typeof(int))
    {
        var token = context.ParseNextToken();
        int parsedInt32 = token.ParseToDotnetInt32();
        // This will not box which might be critical to performance
        return Unsafe.As<int, TResult>(ref parsedInt32); 
    }
    // other cases omitted for brevity's sake
}

Unsafe.As will be replaced by the JIT with efficient machine code instructions, as you can see in the official CoreFX repo:

Source Code of Unsafe.As

Solution 4 - C#

If you're checking for explicit types, why are you declaring those variables as T's?

T HowToCast<T>(T t)
{
    if (typeof(T) == typeof(string))
    {
        var newT1 = "some text";
        var newT2 = t;  //this builds but I'm not sure what it does under the hood.
        var newT3 = t.ToString();  //for sure the string you want.
    }

    return t;
}

Solution 5 - C#

You will also get this error if you have a generic declaration for both your class and your method. For example the code shown below gives this compile error.

public class Foo <T> {

	T var;
	
	public <T> void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
		this.var = cls.newInstance();
	}
	
}

This code does compile (note T removed from method declaration):

public class Foo <T> {

	T var;
	
	public void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
		this.var = cls.newInstance();
	}
	
}

Solution 6 - C#

Change this line:

if (typeof(T) == typeof(string))

For this line:

if (t.GetType() == typeof(string))

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
QuestionAlexView Question on Stackoverflow
Solution 1 - C#SLaksView Answer on Stackoverflow
Solution 2 - C#DoggettView Answer on Stackoverflow
Solution 3 - C#feO2xView Answer on Stackoverflow
Solution 4 - C#Austin SalonenView Answer on Stackoverflow
Solution 5 - C#JohnView Answer on Stackoverflow
Solution 6 - C#SerchView Answer on Stackoverflow