Подтвердить что ты не робот

Разница между "С++ void Pointer" и "С# var"

Во время обучения С# этот вопрос пришел мне на ум. В чем разница между void и var? Вот два примера, которые я хотел бы поделиться:

void * voidInt = (void *) 7;
void * voidChar = (void *) 'F';
void * voidCharArray = (void *) "AbcString";

И это пример var:

var varInt = 7;
var varChar = 'F';
var varCharArray = "AbcString";
  • Является ли void анонимным типом данных?
  • Если да, то что является основным разница между var и void?

Может кто-нибудь помочь мне очистить эту ситуацию?

4b9b3361

Ответ 1

Другие ответы здесь довольно хорошие, но я думаю, что они не понимают основные принципы. Это основные принципы, которые вы путаете, поэтому позвольте им обратиться к ним.

  • Переменная - это место хранения, содержащее значение.
  • Переменная связана с типом.
  • Локальная переменная имеет имя.

So voidInt, voidChar, voidCharArray, varInt, varChar и varCharArray - все переменные, и все они имеют связанные с ними типы. Каждой переменной может быть присвоено значение этого типа или вывести значение этого типа в зависимости от того, записывается ли переменная или читается.

Хорошо, теперь что такое указатели?

  • Тип имеет соответствующий тип указателя. (Обратите внимание, что в небезопасных С# только неуправляемые типы имеют соответствующие типы указателей.)
  • Тип void * - это специальный тип указателя.
  • Указатель - это значение.
  • Указатель типа T* может быть разыменован для получения переменной типа T. T* не должен быть void*.
  • Указатель может быть явно преобразован в любой тип интеграла или из него, хотя эти операции могут потерять информацию и зависят от деталей реализации.
  • Любое значение указателя может быть неявно преобразовано в void*.
  • Любое значение void* может быть явно преобразовано в любое значение типа указателя.

А что такое var в С#?

  • var является "синтаксическим сахаром", который сообщает компилятору вывести тип переменной из initialzier, а не требовать, чтобы он был выписан.

А что такое "анонимные типы" на С#?

  • Некоторые выражения в С# имеют тип, который не объявлен и не имеет имени; они известны как "анонимные" типы.

Итак, теперь мы можем посмотреть вашу программу и посмотреть, что делает каждая строка.

void * voidInt = (void *) 7;

voidInt - это переменная типа void*. Значением, назначенным ему, является преобразование целого числа 7 в указатель, что почти наверняка является указателем мусора для любой современной операционной системы. Этот код по сути бессмысленен.

Более разумный код:

int myInt = 7;
int* intPtr = &myInt;
void* voidInt = intPtr;

Это означает, что myInt - это переменная, которая содержит значение 7, intPtr - переменная, которая содержит указатель; когда этот указатель разыменован, он генерирует переменную myInt. voidInt - это переменная, которая содержит любой указатель, а значение, считанное из intPtr, является указателем. Итак, теперь voidInt и intPtr содержат указатель на переменную myInt.

void * voidChar = (void *) 'F';

То же самое здесь. Символ F обрабатывается как число и преобразуется в значение указателя, которое хранится в переменной. Это неразумно. Разумный код будет примерно таким:

char myChar = 'F';
void *voidChar = &myChar;

Но это имеет смысл:

void * voidCharArray = (void *) "AbcString";

Строковый литерал в С++ конвертируется в char*, который является указателем на хранилище для первого символа, и этот указатель можно конвертировать в void*.

Как насчет этого?

var varInt = 7;
var varChar = 'F';
var varCharArray = "AbcString";

Это просто приятный способ написать

int varInt = 7;
char varChar = 'F';
string varCharArray = "AbcString";

Каждая переменная имеет свой заданный тип, и каждое присваивание сохраняет значение этого типа в переменной.

Как насчет анонимных типов?

var anon = new { X = 123, Y = 456 };

Это делает переменную анонимного типа, где анонимный тип имеет два свойства X и Y как тип int. Тип не имеет имени, поэтому нет способа записать тип объявления, поэтому var должен использоваться.

Ключевое значение здесь - убедиться, что у вас есть понимание основ: указатели являются значениями, они могут быть разыменованы, и при этом создается переменная. Поскольку указатели являются значениями, они могут сами храниться в переменных типа указателя. Это почти не имеет отношения к var, что является приятным способом в С#, чтобы заставить компилятор выполнить работу по выяснению того, какой тип должен иметь переменная.

Ответ 2

void и var действительно не имеют ничего общего:

  • void (как используется переменными указателя в C и С++) означает неуказанный (не определенный) тип. void* не разрешены * в управляемом С# (хотя очень слабый тип, такой как ссылка object, может быть близким приближением). Как правило, типы void* должны быть повторно отобраны, чтобы быть полезными.

  • Однако void возвращаемые типы из метода/функции означают одинаковые на обоих языках, что означает, что нет возвращаемого значения (например, Unit в Scala)

  • В отличие от var в С# определяется неявно типизированная переменная - переменная по-прежнему имеет сильный тип, но фактический тип выведенный с правой стороны во время компиляции.

например.

var v1 = "Foo"; // v1 is a string, because it is inferred from the right hand side
var v2 = XDocument.Parse(@"c:\temp\foo.xml"); // v2 is the return type of the function

var часто требуется при использовании анонимных типов - возможно, именно там вы установили соединение между var и анонимными типами:

var v3 = new { Name = "Foo", Value = 123};  // v3 is strongly typed, anonymous class.

var особенно полезен для назначения переменных возвращаемым значениям выражений LINQ, где типы могут быть довольно сложными:

var v3 = db.Persons
      .Join(db.Cities, p => p.CityId, c => c.Id, (p, c) => new {Person = p, City = c})
      .GroupBy(pc => pc.City.Name);

* На самом деле, это не совсем так, вы можете использовать void * в С# с небезопасно

Edit

Еще одна вещь, заслуживающая упоминания, что с С# 6, что неявное var типирование может использоваться только для локальных переменных, то есть С# не поддерживает неявное типирование возвращаемых типов метода (в отличие от функциональных языков, таких как Scala, где компилятор в большинстве случаев также может вывести возвращаемый тип метода).

Ответ 3

  • В небезопасном контексте эквивалент С++ void* в С# равен void*. Любой тип указателя данных может быть назначен void*.
  • В безопасном контексте object (свободно) соответствует соответствующей концепции. Любой экземпляр класса/интерфейса/структуры может быть назначен ему.
  • В С++ эквивалент С# var равен auto. Когда используется для объявления и инициализации локальной переменной, она действует как тип выражения, назначенного этой переменной, если это возможно.

Ответ 4

Вы можете сделать это с помощью указателя void С++:

void * val = (void *) 7;
val = (void *) "Abcd";

Но вы не можете сделать это с помощью С# var:

var val = 7;
val = "abcd";

Это приведет к ошибке.

Update

Если вы хотите добиться аналогичного поведения void *, вы можете использовать dynamic.

dynamic val = (dynamic) 7;
val = (dynamic) "ABC";

Когда используется var, фактический тип переменной определяется во время компиляции. Но, когда используется dynamic, фактический тип переменной определяется во время выполнения.