截至链接: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
等显式类型。
为什么我会发现这样的错误?
答案 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]) + "]");
答案 2 :(得分:2)
在这种情况下,Session
是HttpSessionState实现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枚举器返回的任何类型。在大多数情况下,指定不同的类型就像是一个类型转换。
仅仅因为某个东西是一个类或一个盒子(这意味着它是一个对象)并不意味着编译器对该对象实际上是什么有所了解。事实上,我认为标准建议如果某个东西成为一个对象,编译器就不应该自动转换它,即使它知道它实际上是什么类型(也许它从上面几行知道)