C#确实var有一个强类型?

时间:2013-03-09 01:57:14

标签: c# runtime type-conversion var rtti

截至链接:http://msdn.microsoft.com/en-us/library/bb383973.aspx

...隐式类型的局部变量是强类型的,就像你自己声明了类型一样, 但是编译器确定类型 ......

但我有这样的代码:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (Session["user"] == null) Response.Redirect("Default.aspx");

        StringBuilder sb = new StringBuilder();

        foreach (var item in Session)
        {
            sb.Append("Session Parameter: [");
            sb.Append(item);
            sb.Append("]<p />Guid Value: [");
            sb.Append(Session[item] + "]");
        }

        Response.Write(sb.ToString());
    }

我在Visual Studio中遇到这样的错误:

参数1:无法将“对象”转换为“字符串”:

 sb.Append(Session[item] + "]");

item在运行时标识为我在调试器中查看的string类型。

当我在msdn /书中阅读var时,我认为var与RTTI内容无关。编译器只是在编译时使用隐式类型更改变量,如string, int等显式类型。

为什么我会发现这样的错误?

7 个答案:

答案 0 :(得分:8)

C#中的var声明是强类型的,但在这种情况下,您正在处理值Session中的非泛型集合类型。这会导致C#为object的类型选择item,因此您在稍后的错误中尝试在需要item的位置使用string

对于非泛型集合,您仍需要在foreach块中显式键入迭代器变量

foreach(string item in Session) { 
  ...
}

答案 1 :(得分:3)

“为什么我会抓到这样的错误?” - 因为sb.Append(Session[item] + "]");期待一个字符串 - 所以你需要将Session[item]强制转换为字符串:

sb.Append(((string)Session[item]) + "]");

根据MSDN文章How to: Read Values from Session State

答案 2 :(得分:2)

在这种情况下,SessionHttpSessionState实现IEnumerable(尽管如果实现IEnumerable<object>会发生同样的情况),因此您的var会被映射由编译器进入:

  foreach (object item in Session)
  {

在这种情况下,这可能是IEnumerable,因此您需要在foreach中明确指定类型:

  foreach (string item in Session)
  {

对于非通用foreach集合,IEnumerable允许这样做。

至于你的主要问题:

  

C#确实var有一个强类型吗?

是。在这种情况下,集合本身不提供强类型,因此var使用System.Object

答案 3 :(得分:1)

你是对的,var是静态输入的(即在编译时)。但是,var的静态类型来自上下文,它允许编译器派生var的类型。

如果Session实现IEnumerable,则编译器可以派生的唯一类型是object,从而导致您描述的错误。

如果Session已实施,IEnumerable<string>,则循环中的var将等同于string,而不是object

答案 4 :(得分:1)

在您的示例中,它归结为什么类型的集合Session。在这种情况下,它是对象的集合,因此编译器将var item转换为object item

答案 5 :(得分:1)

正如其他答案所示,Session的Item属性(默认索引器)属于object类型。这就是为什么你从索引器中获取一个对象 - 它是它的返回类型。

http://msdn.microsoft.com/en-us/library/k8s0kehy(v=vs.100).aspx

答案 6 :(得分:1)

因为对象是一种不同的类型。非常类似于为什么派生类与其基类不同(例如:class D : B{})。所有类类型都继承Object,我相信不会继承值(struct)。它们需要装箱。Session集合只是说它有一堆物体,任何东西都可以在那里。运行时不会尝试检查,除非您要求它(通过类型转换或关键字)。 (有关下面编译器的更多信息)

该foreach中的var表示此变量(item)应该是Session枚举器返回的任何类型。在大多数情况下,指定不同的类型就像是一个类型转换。

仅仅因为某个东西是一个类或一个盒子(这意味着它是一个对象)并不意味着编译器对该对象实际上是什么有所了解。事实上,我认为标准建议如果某个东西成为一个对象,编译器就不应该自动转换它,即使它知道它实际上是什么类型(也许它从上面几行知道)