铸造泛型参数

时间:2013-11-20 18:56:07

标签: c# generics

你能解释为什么第一行代码会给我编译错误而下一行代码却没有。

public void DoStuff<T>(T obj)
{
 Int32 x = (Int32) obj; // 1. Error
 Int32 y=(Int32)(Object)obj; //2. Works fine
}

5 个答案:

答案 0 :(得分:4)

为了进行强制转换,您需要在编译时知道如何从一种类型转换为另一种类型。例如:

long l = 34;
int i = (int)l;

这是有效的,因为编译器知道如何将long转换为int。它还知道如何将object转换为int

object o = 42;
int i = (int)o;

但是,并非所有类型都可以投射到int

string s = "48";
int i = (int)s; // This will not compile.

由于您的通用符可以表示任何类型,因此您不能仅为任何类型强制转换为int。你必须先把它投射到可以投射到int的东西上。因为任何东西都可以投射到objectobject并被投射到任何东西,所以你的双重投射会起作用。

答案 1 :(得分:0)

将泛型类型变量转换为其他类型是非法的,除非您要转换为与约束兼容的类型:

 private static void CastingAGenericTypeVariable1<T>(T obj) {
Int32 x = (Int32) obj; // Error
String s = (String) obj; // Error
}

编译器在上面的两行上都发出错误,因为T可以是任何类型,并且没有 保证演员阵容成功。您可以通过首先转换为Object来修改此代码以使其编译:

    private static void CastingAGenericTypeVariable2<T>(T obj) {   
   Int32 x = (Int32) (Object) obj; // No error
   String s = (String) (Object) obj; // No erro``r
  }

虽然此代码现在将编译,但CLR仍可能在运行时抛出InvalidCastException。

如果您尝试强制转换为引用类型,则还可以使用C#作为运算符。这里修改了代码以使用带字符串的as运算符(因为Int32是值类型):

 private static void CastingAGenericTypeVariable3<T>(T obj) {
  String s = obj as String; // No error
  }

This is from CLR via C#

答案 2 :(得分:0)

T可以是任何类型,但编译器会识别出对Int32的强制转换仅适用于某些类型,因此编译错误。

答案 3 :(得分:0)

如果你有一个泛型方法,你可能不想转换为int。通过重载或其他方法几乎可以肯定有更好的方法。

但是......如果您决定需要这样做,您可以安全地执行以下两种方法中的任何一种......

if (obj is Int32)
{
    // do stuff
}

或..

Int32? z = obj as Int32?
if (z != null)
{
  // do stuff
}

答案 4 :(得分:0)

规范解释了这种行为:

6.2.7涉及类型参数的显式转换

  

以上规则不允许直接显式转换   非约束类型参数到非接口类型,可能是   奇怪。这个规则的原因是为了防止混淆和制造   这种转换的语义清晰。例如,考虑一下   以下声明:

class X<T>
{
    public static long F(T t) {
        return (long)t;             // Error 
    }
}
  

如果允许将t直接显式转换为int,则为1   可能很容易预期X.F(7)将返回7L。但是,它   不会,因为标准的数字转换只是   当绑定时已知类型为数字

时考虑
相关问题