В C#, когда ключевое слово var отличается от его ввода?
Вопрос
В 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, чтобы определить тип.