В C#, когда ключевое слово var отличается от его ввода?

StackOverflow https://stackoverflow.com/questions/391462

  •  23-08-2019
  •  | 
  •  

Вопрос

В 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.

Редактировать:правильный код теперь прилагается.

Это было полезно?

Решение

Думаю, я вижу проблему.DataRowCollection не является универсальным, поэтому единственное, что известно компилятору, — это наличие объектов типа Object.Если бы это была общая структура данных, это сработало бы.

Другие советы

Этот:

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();
        }
    }
}

работает так, как и ожидалось, он дает мне intellisense, показывающий как Bleh, так и Blah, в Visual Studio 2008.

У тебя было что-то нравиться это или точно что?Могут быть и другие вещи, которые сбивают с толку IntelliSense, кроме кода, который вы показали.

Чтобы ответить на реальный вопрос.Единственная разница между написанием типа и использованием var, заключается в том, что в некоторых случаях вы должен используйте var, если у вас просто нет подходящего типа.Это, если я не ошибаюсь, актуально только тогда, когда вы используете анонимные типы.

Других различий нет, и компилятор выберет тот же тип слева, что и справа.

Редактировать:Благодаря @Телос для указания на то, что одно отличие состоит в том, что при использовании var вы, конечно, должны присвоить переменной значение во время объявления, поскольку тип выражения в правой части используется для определения типа переменной слева: сторона руки.При указании типа вы, конечно, можете отказаться от присвоения ему значения.

Я предполагаю, что somethingThatReturnsY на самом деле заявил вернуть X - даже если на практике он возвращает Y.Я ожидаю, что если вы заявите y как Y y = somethingThatReturnsY(); он не сможет скомпилироваться.

Правила для var довольно просты (для случаев, когда это работает - существуют различные ограничения, которые мешают вам делать var x = null; и т. д.

Если вы думаете var действительно делает что-то неправильно, опубликуйте, пожалуйста, короткую, но полную программу для демонстрации.

Я попытался воспроизвести это с помощью следующего кода в консольном приложении.

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 работает правильно, и Отражатель показывает, что j имеет тип y.Я предполагаю, что если вы столкнулись с чем-то подозрительным, это более сложно, чем простой случай здесь.

Я также использую Visual Studio 2008 RTM.

DataTable.Rows возвращает DataRowCollection, который реализует InternalDataCollectionBase, который, в свою очередь, реализует ICollection и IEnumerable.Код

foreach(DataRow row in dt.Rows) { }

преобразует каждый элемент DataRowCollection в DataRow.Вы можете продемонстрировать это, изменив его на

foreach(int row in dt.Rows) { }

который компилируется, но выдает InvalidCastException.

Если DataRowCollection реализован IEnumerable<DataRow> тогда это не будет компилироваться, и использование var будет вводить каждый объект в списке как DataRow.

Я не думаю, что вы предоставили достаточно информации в примере кода.Я сделал небольшую программу, чтобы попытаться имитировать описанное вами поведение:

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?

Он работает так, как должен.Он присваивает тип объекта «объект», когда компилятор не может определить правильный тип данных.

Когда вы используете ключевое слово foreach, доступ к DateRowCollection осуществляется через интерфейс IEnumerable.Конкретный метод, используемый для доступа к DataRow, называется Current и возвращает объект.Таким образом, ключевое слово var просматривает возвращаемое значение метода Current, чтобы определить тип.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top