类型“ T”的值不能转换为

这可能是一个新手的问题,但令人惊讶的是谷歌并没有给出答案。

我有一种相当人工的方法

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


return t;
}

从一个 C + + 的背景来看,我期望这个工作。但是,对于上述两个分配,都未能使用“无法隐式地将类型‘ T’转换为字符串”和“无法将类型‘ T’转换为字符串”进行编译。

我要么是在概念上做错了什么,要么就是语法有问题。请帮我把这个问题解决一下。

谢谢!

142460 次浏览

即使它在 if块中,编译器也不知道 Tstring
因此,它不允许您进行转换(出于同样的原因,您不能将 DateTime转换为 string)

您需要转换为 object(任何 T都可以转换为 object) ,然后从 object转换为 string(因为 object可以转换为 string)。
例如:

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

两条线路都有同样的问题

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

编译器不知道 T 是一个字符串,因此无法知道如何赋值它。 但既然你已经检查过了,你可以用

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

您不需要强制转换 t,因为它已经是一个字符串,还需要添加约束

where T : class

如果要检查显式类型,为什么要将这些变量声明为 T

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

换一行:

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

这句话是:

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

如果您的类和方法都有泛型声明,您也会得到这个错误。例如,下面显示的代码给出了这个编译错误。

public class Foo <T> {


T var;


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


}

这段代码可以编译(注意,从方法声明中删除了 T) :

public class Foo <T> {


T var;


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


}

我知道 OP 在这个问题中从通用解析器发布的类似代码。从性能角度来看,您应该使用 Unsafe.As<TFrom, TResult>(ref TFrom source),它可以在 系统。运行时。编译器服务。不安全 NuGet 包中找到。它避免了在这些方案中对值类型进行装箱。我还认为 Unsafe.As产生的机器代码比转换两次(使用 (TResult) (object) actualString)产生的机器代码要少,但是我还没有检查过。

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将被带有高效机器码指令的 JIT 所取代,正如你在正式的 CoreFX 回购协议中看到的:

Source Code of Unsafe.As