2

C# 3.0 引入了var关键字。编译后,编译器将为您插入正确的类型。这意味着它甚至可以在 2.0 运行时上运行。到现在为止还挺好。但是前几天我发现了一个案例,var关键字将被替换为只是对象,因此不够具体。假设你有类似的东西:

var data = AdoMD.GetData(...); // GetData returns a DataTable

foreach (var row in data.Rows)
{
     string blah = (string)row[0]; // it fails since it's of type object
}

当我尝试使用行时,IntelliSense和编译器都告诉我它是对象类型。data.Rows是类型System.Data.DataRowCollection。以下作品:

var data = AdoMD.GetData(...); // GetData returns a DataTable

foreach (DataRow row in data.Rows)
{
     string blah = (string)row[0]; // works since it now has the right type
}

这不是关于 var 使用的问题,这里有一个线程

我正在使用 Visual Studio 2008 SP1 顺便说一句。

编辑:现在附上正确的代码。

4

8 回答 8

10

我想我看到了问题。DataRowCollection 是非泛型的,因此编译器唯一知道的是它包含 Object 类型的对象。如果它是一个通用的数据结构,这将是可行的。

于 2008-12-30T16:57:31.227 回答
3

这:

using System;

namespace Test
{
    public class X
    {
        public String Bleh;
    }

    public class Y : X
    {
        public String Blah;
    }

    public static class Program
    {
        public static void Main()
        {
            var y = SomeFunctionThatReturnsY();
            // y. <-- this gives me both Blah and Bleh in the dropdown
        }

        public static Y SomeFunctionThatReturnsY()
        {
            return new Y();
        }
    }
}

按预期工作,它让我在 Visual Studio 2008 中显示 Bleh 和 Blah 的智能感知。

你有类似的东西或者完全是这样的吗?除了您显示的代码之外,可能还有其他事情会触发智能感知。

回答实际问题。拼出类型和使用 之间的唯一区别var是,在某些情况下,当您根本没有正确的类型时,您必须使用 var。如果我没记错的话,这仅在您使用匿名类型时才相关。

没有其他区别,编译器将在左侧选择与右侧相同的类型。

编辑:感谢@Telos指出一个区别是,当使用 var 时,您当然必须在声明时给变量一个值,因为右侧表达式的类型用于指示左边的变量。在拼写类型时,您当然可以选择不给它一个值。

于 2008-12-24T14:06:42.950 回答
2

我的猜测是它somethingThatReturnsY实际上被声明为返回 X - 即使它在实践中返回 Y。我希望如果您声明yY y = somethingThatReturnsY();它将无法编译。

的规则var非常简单(对于它有效的情况 - 有各种限制阻止你这样做var x = null;等等。

如果您认为var确实做错了事,请发布一个简短但完整的程序来演示。

于 2008-12-24T14:20:33.467 回答
1

我试图在控制台应用程序中使用以下代码重现这一点。

class Program
{
    static void Main(string[] args)
    {
        var j = returny();
        j.blah();
    }

    private static y returny()
    {
        return new y();
    }
}

class x
{
}

class y : x
{
    public void blah() { }
}

这可以按预期工作,IntelliSense 是正确的,并且Reflector显示它j的类型是y. 我的猜测是,如果您遇到可疑的事情,那么这里的简单情况会更复杂。

我也在使用 Visual Studio 2008 RTM。

于 2008-12-24T14:10:14.690 回答
1

DataTable.Rows 返回实现 InternalDataCollectionBase 的 DataRowCollection,后者又实现 ICollection 和 IEnumerable。编码

foreach(DataRow row in dt.Rows) { }

将 DataRowCollection 中的每个项目转换为 DataRow。您可以通过将其更改为来证明这一点

foreach(int row in dt.Rows) { }

编译但抛出 InvalidCastException。

如果实现了 DataRowCollection IEnumerable<DataRow>,则不会编译,并且使用 var 会将列表中的每个对象键入为 DataRow。

于 2010-01-27T18:52:30.497 回答
0

我不相信您在示例代码中提供了足够的信息。我做了一个小程序来尝试模仿你描述的行为:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        var y = SomeFunctionThatReturnsY();

        MessageBox.Show(y.bla);

        return;
    }

    private Y SomeFunctionThatReturnsY()
    {
        return new Y();
    }
}

internal class X { }

internal class Y : X
{
    public string bla = "Saw a Y, not an X";
}

但是输出清楚地表明 var 正在解析 Y 类型,而不是 X。

您确定您的函数返回 Y 作为 Y 引用,而不是作为 X 引用吗?

于 2008-12-24T14:20:55.277 回答
0

它可以正常工作。当编译器无法确定正确的数据类型时,它将对象类型作为“对象”。

于 2008-12-30T17:08:29.847 回答
0

当您使用 foreach 关键字时,可以通过 IEnumerable 接口访问 DateRowCollection。用于访问 DataRow 的特定方法称为 Current 并返回一个对象。所以 var 关键字是查看 Current 方法的返回值来推断类型。

于 2010-01-27T18:37:08.253 回答