"C++ void Pointer" 和 "C# var" 之间的区别
Difference between "C++ void Pointer" and "C# var"
在学习C#的过程中,我想到了这个问题。 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
之间的区别?
谁能帮我解决这个问题?
void
和 var
没有任何共同点:
void(C 和 C++ 中的指针变量所使用的)表示未指定(不是确定的)类型。 void*
在托管 C# 中是不允许的*(尽管非常弱的类型,例如 object
引用可能是一个近似值)。通常,void*
类型需要重新转换才能使用。
但是void
return类型来自方法/函数的意思相同
在这两种语言中,这是为了传达 没有 return 值 (就像 Scala 中的 Unit
)
- 相比之下,C# 中的
var
定义了一个 implicitly typed variable - 变量仍然具有强类型,但实际类型是在编译时从右侧推断的。
例如
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 表达式的 return 值特别有用,其中类型可能非常复杂:
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);
* 实际上,这并不完全正确,您可以在 C# 中使用 void* 和 unsafe
编辑
另外值得一提的是,从 C#6 开始,隐式 var
类型只能用于局部变量,即 C# 不支持方法 return 类型的隐式类型(不像 Scala 这样的函数式语言,在大多数情况下编译器也可以推断出方法的 return 类型)。
你可以用 c++ void pointer 来做到这一点:
void * val = (void *) 7;
val = (void *) "Abcd";
但是你不能用 c# var:
var val = 7;
val = "abcd";
这将引发错误。
更新
如果您想实现与 void *
类似的行为,您可以使用 dynamic
。
dynamic val = (dynamic) 7;
val = (dynamic) "ABC";
当使用var
时,变量的实际类型在编译时确定。但是,当使用 dynamic
时,变量的实际类型在 运行 时确定。
- 在不安全的上下文中,C# 中 C++
void*
的等价物是 void*
。任何数据指针类型都可以分配给 void*
.
- 在安全上下文中,
object
是(松散地)对应的概念。任何 class/interface/struct 个实例都可以分配给它。
- C++ 中 C#
var
的等价物是 auto
。当用于声明和初始化局部变量时,如果可能的话,它充当分配给该变量的表达式的类型。
这里的其他答案都很好,但我认为他们没有弄清楚基本原理。这是您感到困惑的基本原理,所以让我们解决这些问题。
- 一个变量是一个包含值的存储位置。
- 变量与类型关联。
- 一个局部变量有一个名称。
所以voidInt
、voidChar
、voidCharArray
、varInt
、varChar
和varCharArray
都是变量,它们都有 类型 与之关联。每个变量都可以分配该类型的值或产生该类型的值,具体取决于变量是被写入还是从中读取.
好的,那么什么是指针?
- 一个类型有对应的指针类型。 (请注意,在不安全的 C# 中,只有 非托管类型 具有相应的指针类型。)
void *
类型是一种特殊的指针类型。
- 一个指针是一个值。
- 类型
T*
的指针可以 取消引用 以生成类型 T
的 变量 。 T*
不能是 void*
.
- 指针可以显式转换为任何整数类型或从任何整数类型转换,尽管这些操作允许丢失信息并且取决于实现细节。
- 任何指针值都可以隐式转换为
void*
。
- 任何
void*
值都可以显式转换为任何指针类型值。
C# 中的 var
是什么?
var
是一个 "syntactic sugar",它告诉编译器从 initialzier 推断变量的类型,而不是要求它被写出来。
C#中的"anonymous types"是什么?
- C# 中的某些表达式具有未声明且没有名称的类型;这些被称为 "anonymous" 类型。
所以现在我们可以查看您的程序并查看每一行的作用。
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";
C++ 中的字符串文字可转换为 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 };
这将创建一个匿名类型的变量,其中匿名类型具有两个类型为 int
的属性 X 和 Y。该类型没有名称,因此无法在声明中写出类型,因此必须使用 var
。
这里的关键是确保您掌握了基础知识:指针是值,它们可能是取消引用,这样做会产生一个变量。由于指针是 values,它们本身可能存储在指针类型的 variables 中。这几乎与 var
无关,后者是 C# 中让编译器确定变量类型的一种令人愉快的方式。
在学习C#的过程中,我想到了这个问题。 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
之间的区别?
谁能帮我解决这个问题?
void
和 var
没有任何共同点:
void(C 和 C++ 中的指针变量所使用的)表示未指定(不是确定的)类型。
void*
在托管 C# 中是不允许的*(尽管非常弱的类型,例如object
引用可能是一个近似值)。通常,void*
类型需要重新转换才能使用。但是
void
return类型来自方法/函数的意思相同 在这两种语言中,这是为了传达 没有 return 值 (就像 Scala 中的Unit
)- 相比之下,C# 中的
var
定义了一个 implicitly typed variable - 变量仍然具有强类型,但实际类型是在编译时从右侧推断的。
例如
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 表达式的 return 值特别有用,其中类型可能非常复杂:
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);
* 实际上,这并不完全正确,您可以在 C# 中使用 void* 和 unsafe
编辑
另外值得一提的是,从 C#6 开始,隐式 var
类型只能用于局部变量,即 C# 不支持方法 return 类型的隐式类型(不像 Scala 这样的函数式语言,在大多数情况下编译器也可以推断出方法的 return 类型)。
你可以用 c++ void pointer 来做到这一点:
void * val = (void *) 7;
val = (void *) "Abcd";
但是你不能用 c# var:
var val = 7;
val = "abcd";
这将引发错误。
更新
如果您想实现与 void *
类似的行为,您可以使用 dynamic
。
dynamic val = (dynamic) 7;
val = (dynamic) "ABC";
当使用var
时,变量的实际类型在编译时确定。但是,当使用 dynamic
时,变量的实际类型在 运行 时确定。
- 在不安全的上下文中,C# 中 C++
void*
的等价物是void*
。任何数据指针类型都可以分配给void*
. - 在安全上下文中,
object
是(松散地)对应的概念。任何 class/interface/struct 个实例都可以分配给它。 - C++ 中 C#
var
的等价物是auto
。当用于声明和初始化局部变量时,如果可能的话,它充当分配给该变量的表达式的类型。
这里的其他答案都很好,但我认为他们没有弄清楚基本原理。这是您感到困惑的基本原理,所以让我们解决这些问题。
- 一个变量是一个包含值的存储位置。
- 变量与类型关联。
- 一个局部变量有一个名称。
所以voidInt
、voidChar
、voidCharArray
、varInt
、varChar
和varCharArray
都是变量,它们都有 类型 与之关联。每个变量都可以分配该类型的值或产生该类型的值,具体取决于变量是被写入还是从中读取.
好的,那么什么是指针?
- 一个类型有对应的指针类型。 (请注意,在不安全的 C# 中,只有 非托管类型 具有相应的指针类型。)
void *
类型是一种特殊的指针类型。- 一个指针是一个值。
- 类型
T*
的指针可以 取消引用 以生成类型T
的 变量 。T*
不能是void*
. - 指针可以显式转换为任何整数类型或从任何整数类型转换,尽管这些操作允许丢失信息并且取决于实现细节。
- 任何指针值都可以隐式转换为
void*
。 - 任何
void*
值都可以显式转换为任何指针类型值。
C# 中的 var
是什么?
var
是一个 "syntactic sugar",它告诉编译器从 initialzier 推断变量的类型,而不是要求它被写出来。
C#中的"anonymous types"是什么?
- C# 中的某些表达式具有未声明且没有名称的类型;这些被称为 "anonymous" 类型。
所以现在我们可以查看您的程序并查看每一行的作用。
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";
C++ 中的字符串文字可转换为 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 };
这将创建一个匿名类型的变量,其中匿名类型具有两个类型为 int
的属性 X 和 Y。该类型没有名称,因此无法在声明中写出类型,因此必须使用 var
。
这里的关键是确保您掌握了基础知识:指针是值,它们可能是取消引用,这样做会产生一个变量。由于指针是 values,它们本身可能存储在指针类型的 variables 中。这几乎与 var
无关,后者是 C# 中让编译器确定变量类型的一种令人愉快的方式。