Value of type 'T' cannot be converted to
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;
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
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: