无法隐式将类型 'T' 转换为 'Int'。

26
尝试在我的代码中调用此函数时,我得到了标题中的错误。同时,“+=”运算符无法应用于类型为“int”和“T”的操作数。
public int Change<T>(Stats type, T value)
    {
        Dictionary<string, string> temp = new Dictionary<string, string>();
        temp = sql.Query(string.Format("SELECT {0} FROM player WHERE fbId='{1}'", type.ToString(), FBId));
        if (typeof(T) == typeof(int))
        {
            int t = Convert.ToInt16(temp[type.ToString()]);
            t += value;
            if (t < 0) return -1;
            PlayerStats[type] = t;

        }
        sql.Upload(string.Format("UPDATE player SET {0}='{1}' WHERE fbId='{2}'", type.ToString(), PlayerStats[type], FBId));
        return 0;
    }

我通过以下方式调用函数:

Change<int>(type, 1);

16
如果这个方法并不通用,那么使它成为通用方法的意义何在? - dlev
5
你有多大把握Bobby Tables不会破坏你的数据库? - Anthony Pegram
1
我会对你的SQL接口做一些处理...那似乎是一个注入攻击的邀请。 - Jeremy Holovacs
6
我注意到你的“问题”实际上并没有包含一个问题,而是包含了一段正确编译器行为的描述。 你有问题吗?根据你的代码,我怀疑你认为C#泛型是C++模板的一种。它们不是。一个C++模板在每次构建时重新编译,因此只需要对实际的构造正确即可。而C#泛型实际上是通用的;它要求对于任何可能的构造都正确,而不仅仅是你实际使用的构造。任意的T类型不能添加到int类型中。 - Eric Lippert
可能是重复的问题:无法隐式转换类型“Int”为“T” - nawfal
6个回答

25
您可以尝试像这样转换该值...
t += (int)value; 

或者
t+= Convert.ToInt32(value);

你需要导入什么才能使用“Convert”? - Big Money
18
(int)value无法正常工作,会出现错误“无法将类型'T'转换为'int'”。 - Yatharth Varshney
1
正如@yatharthvarshney所说,(int)valuevalue是泛型类型T时无法工作。您必须编写(int)(object)value,这会引入装箱和拆箱。 - Thomas Flinkow

17

还有一种方法(需要进行对象转换而不是打字错误)

t += (int)(object)value;

或者使用dynamic,通过使用dynamic,您可以做更多的事情,例如隐式转换

或者使用Int32 - Int32和int都在内部作为结构体。没有性能损失


1
不确定是否将装箱/拆箱转换添加到明确使用整数的通用函数中是一个好主意。 - Jviaches
@Jviaches 只要 value 的运行时类型 恰好Int32,它就可以工作。但是你不能直接将装箱的 Int64 强制转换为 Int32,例如 (Int32)(Object)(someInt64Value) 将失败。但是这个会成功:(Int32)(Object)(Int32)(someInt64Value) - 这有点违背了装箱的初衷。但如果最左边的 Int32 是一个泛型 T,那么你需要手动测试 typeof(T) == typeof(Int32),呃。 - Dai

9

您可以设置约束条件:

public int Change<T>(Stats type, T value) where T : IConvertible

然后:

var intValue = value.ToInt32();

我相信默认情况下这会导致value被装箱,但是如果你添加一个where T : struct, IConvertible的约束条件,那么CSC/JIT就不会装箱value - Dai

2
它不知道如何将你的 T 添加到数字中,因为它不知道 T 的类型会是什么。
t += Convert.ToInt32(value);

但是既然您正在将 int 加到 int 并返回 int,那么为什么不放弃通用参数并将其改为:
public int Change(Stats type, int value)  

如果您希望针对不同类型实现不同的行为,并且确实需要相同的方法名称,那么可以尝试以下方法而不是测试类型:

 public int Change(Stats type, string value) 
 public int Change(Stats type, DateTime value)  

因为我可能会传递一个整数、布尔值或字符串。这完全取决于何时需要调用Change()函数。 - David W
@David,这个建议是有道理的。到目前为止,您已经向我们展示了您想要执行整数的自定义逻辑。至少,您可以考虑使用Change(Stats type, int value)Change<T>(Stats type, T value)重载。当类型对于操作不重要时,泛型非常有用。您已经向我们展示了一个类型很重要的实例。 - Anthony Pegram
你只是使用了泛型类型来定义方法的逻辑/流程,最好创建一些重载,这样至少可以获得编译器检查是否传递了无效类型,如果您将其开放给您提到的所有类型,那么就不能依赖于泛型类型约束。 - Richard Friend

2

我有一个非常相似的问题。虽然不完全是这里所问的问题,但它可能是一个起点:

    private T GetXValue<T>(XElement xElem, string name)
    {
        try
        {
            object o = xElem.Element(name).Value;
            return (T)Convert.ChangeType(o, typeof(T));
        }
        catch 
        {
            return (T)Activator.CreateInstance(typeof(T), null);
        }
    }

0

你得到的错误是有道理的。虽然你使用int作为类型调用方法,但编译器并不知道这将是情况。

要按照现有方式编译该方法,编译器需要证明你对T执行的操作对于所有T都是有效的——显然这并非事实。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接