简体   繁体   English

几个C#语言问题

[英]Several C# Language Questions

1) What is int ? 1)什么是int Is it any different from the struct System.Int32 ? 它与struct System.Int32有什么不同吗? I understand that the former is a C# alias ( typedef or #define equivalant) for the CLR type System.Int32 . 我知道前者是CLR类型System.Int32的C#别名( typedef#define等效)。 Is this understanding correct? 这种理解正确吗?

2) When we say: 2)当我们说:

IComparable x = 10;

Is that like saying: 就像在说:

IComparable x = new System.Int32();

But we can't new a struct, right? 但是我们不能new一个结构,对吗?

or in C like syntax: 或类似C的语法:

struct System.In32 *x;
x=>someThing = 10;

3) What is String with a capitalized S ? 3)什么是大写的 String I see in Reflector that it is the sealed String class, which, of course, is a reference type, unlike the System.Int32 above, which is a value type. 我在Reflector中看到它是sealed String类,它当然是引用类型,与上面的System.Int32是值类型不同。

What is string , with an uncapitalized s, though? 什么是string ,但不带大写字母s? Is that also the C# alias for this class? 这也是此类的C#别名吗?

Why can I not see the alias definitions in Reflector? 为什么在Reflector中看不到别名定义?

4) Try to follow me down this subtle train of thought, if you please. 4)如果您愿意,请尝试跟随我遵循这种微妙的思路。 We know that a storage location of a particular type can only access properties and members on its interface. 我们知道特定类型的存储位置只能访问其接口上的属性和成员。 That means: 这意味着:

Person p = new Customer();
p.Name = "Water Cooler v2"; // legal because as Name is defined on Person.

but

// illegal without an explicit cast even though the backing 
// store is a Customer, the storage location is of type 
// Person, which doesn't support the member/method being 
// accessed/called.
p.GetTotalValueOfOrdersMade();

Now, with that inference, consider this scenario: 现在,基于这种推断,请考虑以下情形:

int i = 10;

// obvious System.object defines no member to 
// store an integer value or any other value in. 
// So, my question really is, when the integer is 
// boxed, what is the *type* it is actually boxed to. 
// In other words, what is the type that forms the 
// backing store on the heap, for this operation?
object x = i;

Update 更新资料

Thank you for your answers, Eric Gunnerson and Aaronought. 谢谢您的回答,埃里克·冈纳森(Eric Gunnerson)和亚伦(Aaronought)。 I'm afraid I haven't been able to articulate my questions well enough to attract very satisfying answers. 恐怕我无法很好地表达我的问题,以致无法获得令人满意的答案。 The trouble is, I do know the answers to my questions on the surface, and I am, by no means, a newbie programmer. 问题是,我确实从表面上知道我的问题的答案,而我绝不是新手程序员。

But I have to admit, a deeper understanding to the intricacies of how a language and its underlying platform/runtime handle storage of types has eluded me for as long as I've been a programmer, even though I write correct code. 但是,我必须承认,即使我编写了正确的代码,对语言及其底层平台/运行时如何处理类型的复杂性的深入理解也使我难以为继。

  1. int is an alias for System.Int32 . intSystem.Int32的别名。 The types are identical. 类型是相同的。

  2. IComparable x = 10 would be similar to writing var i = 10; IComparable x = i IComparable x = 10类似于写var i = 10; IComparable x = i var i = 10; IComparable x = i . var i = 10; IComparable x = i The compiler chooses what it thinks is the most likely type for the constant, then does an implicit conversion to IComparable . 编译器选择它认为最可能的常量类型,然后隐式转换为IComparable

  3. string is an alias for System.String , similar to #1. stringSystem.String的别名,类似于#1。 You can't see the alias definitions in Reflector because the alias is part of the C# compiler, not the .NET Framework itself. 您无法在Reflector中看到别名定义,因为别名是C#编译器的一部分,而不是.NET Framework本身。 (It's different in VB.NET, for example.) (例如,在VB.NET中是不同的。)

  4. A boxed integer or other value type is a reference to the value. 装箱的整数或其他值类型是对该值的引用。 You could probably think of it as a pointer with some type information attached. 您可能会认为它是带有一些类型信息的指针。 The actual backing type, however, is simply System.Object . 但是,实际的支持类型只是System.Object

I'll respond to questions 2 and 4 only, because it seems the others have been answered satisfactorily already. 我将仅回答问题2和4,因为其他问题似乎已经得到令人满意的回答。

First, let's look at this code from your question: 首先,让我们从您的问题来看这段代码:

int i = 10;
object x = i;

Now, it sounds to me like you're overthinking this. 现在,对我来说,听起来像是您在考虑这个问题。 Yes, it's true that the System.Object type includes no member that would represent the int which has been boxed here. 是的,的确, System.Object类型不包含表示已在此处装箱的int成员。 But that doesn't make this case any different from the other code you posted, which you seem to understand perfectly: 但这与您发布的其他代码没有什么不同,您似乎完全理解:

Person p = new Customer();
p.Name = "Water Cooler v2";

In this case, the Customer class derives from the Person class. 在这种情况下, Customer类从Person类派生。 There are fields, methods, etc. belonging to Customer that are not visible from the context of a Person , but a Customer is a Person . 有一些属于Customer字段,方法等,在Person的上下文中不可见,但是Customer Person In the same way, System.Int32 (which is the same thing as int , as others have pointed out) derives from System.Object . 以同样的方式, System.Int32 (与int相同,正如其他人指出的那样) 派生自 System.Object It is simply that there are operations you can perform on an int that are not visible from the context of an object -- eg, performing addition, etc. But an int is an object . 很简单,您可以在int上执行某些操作,这些操作从object的上下文看不到-例如,执行加法等。但是int object

So the answer to the question "what is actually placed on the heap?" 因此,对“堆中实际放置了什么”这个问题的答案是什么? (the heap, by the way, being an implementation detail of the CLR) is actually quite straightforward: an int is put there. (顺便说一句,堆是CLR的实现细节)实际上非常简单:将int放在那里。

Now, if I may backtrack a bit, I want to respond to this question: 现在,如果我可以回溯一下,我想回答这个问题:

But we can't new a struct, right? 但是我们不能new一个结构,对吗?

Actually, this is inaccurate. 实际上,这是不准确的。 What does the keyword new do? 关键字new什么作用? It sounds like you're thinking in C++ terms, and assuming that if a type is allocated on the stack (again: an implementation detail, mind you), then using the new keyword makes no sense. 听起来您好像在用C ++的方式思考,并假设如果在堆栈上分配了一种类型(同样,请注意实现细节),那么使用new关键字毫无意义。 But in C#, new basically just means you're invoking the type's constructor. 但是在C#中, new基本上仅表示您正在调用类型的构造函数。 And value types (structs) have constructors just like reference types (classes); 值类型(结构)具有与引用类型(类)相同的构造函数。 so yes, this line: 所以是这一行:

IComparable x = 10;

is effectively the same as: 实际上与以下内容相同:

IComparable x = new System.Int32(10); // if System.Int32 had a public
                                      // parameterized constructor
                                      // (which it doesn't, probably
                                      // because that would just
                                      // confuse people)

Now, let me ask you a question: what is the important difference between value types and reference types in .NET? 现在,让一个问题:什么是值类型和引用类型在.NET之间的重要区别? If your answer involves any of the words "stack," "heap," or "allocated," then chances are you're focusing on the wrong thing. 如果您的答案涉及“堆栈”,“堆”或“已分配”中的任何一个,那么您很可能会专注于错误的事情。 What does it matter to us, as developers, where objects are allocated (nitty gritty performance-tweaking-related details aside)? 作为开发人员,分配对象的位置对我们有什么影响(除了坚韧不拔的性能调整相关细节之外)? The important difference, as far as I'm concerned, is simply that value types are passed by value (copied) in method calls . 就我而言, 重要的区别只是值类型通过方法调用中的值(复制)传递 Honestly, that's it. 老实说,就是这样。 That's what matters. 那才是最重要的。

When you view it this way, the big mystery of boxing/unboxing is really not so mysterious. 当您以这种方式查看它时,装箱/拆箱的大奥秘实际上并不是那么神秘。 Let's look at this code again: 让我们再看一下这段代码:

int i = 10;
object x = i;

We say that in the above code, we are "boxing" the integer i in the object x . 我们说在上面的代码中,我们将整数i在对象x But what is meant by this term "boxing"? 但是这个术语“装箱”是什么意思? Is it the same as placing values on the heap? 它与将值放在堆上一样吗? How can this be, if heap vs. stack allocation is an unspecified implementation detail? 如果堆与堆栈分配是未指定的实现细节,那怎么可能?

Remember what I said about value types. 记住我所说的关于价值类型。 The important thing about int being a value type is that whenever you pass an int to a method, you're really passing a copy. int用作值类型的重要之处在于,每当将int传递给方法时,实际上就是在传递副本。 This is the behavior of all value types, which is the same as saying all types deriving from System.ValueType . 这是所有值类型的行为,与说所有派生自System.ValueType类型相同。 But notice that System.Object does not derive from System.ValueType . 但是请注意, System.Object 并非派生自System.ValueType It's the other way around. 相反。 object is a reference type. object是引用类型。

So what "boxing" really means is that you're taking an object that, by virtue of its type, is always passed by value, and casting it to a base type ( object ) that is passed by reference*. 因此,“装箱”的真正含义是,您要获取一个对象,该对象由于其类型而总是按值传递,并将其强制转换为通过引用*传递的基本类型( object )。

If I may offer a somewhat silly analogy: Suppose that you go to some bizarre theme park where the following rules apply: 如果我可以提供一个愚蠢的类比:假设您去了一个遵循以下规则的奇异主题公园:

  1. All people by default ride the Ferris Wheel. 默认情况下,所有人都乘坐摩天轮。
  2. New Yorkers, specifically, ride the Merry-Go-Round instead. 具体地说,纽约人骑着旋转木马。

Before you enter the park, you fill in a little form classifying yourself. 进入公园之前,您需要填写一张小表格对自己进行分类。 After turning in this form, you receive a red wristband if you're from New York, or else a blue wristband. 填写此表格后,如果您来自纽约,则会收到一条红色的腕带,或者收到一条蓝色的腕带。

What if you're from New York but you want to ride the Ferris Wheel? 如果您来自纽约,但想骑摩天轮怎么办? Simple: on the form, instead of filling out your classification as "New Yorker," you just write, "Person." 很简单:在表格上,您不必填写“纽约客”的分类,而只需写“人”。 Bingo, they give you a blue wristband, and you're in. 宾果游戏,他们给了您蓝色的腕带,您就可以进入。

The key distinction to be made here is between what objects can do and how they are treated . 这里要做的主要区别是对象可以做什么和如何对待它们之间。 As I've said multiple times, System.Int32 derives from System.Object , and so you can cast int to object just as easily as you can cast an object of any type to a type from which it derives. 正如我多次说过的, System.Int32 派生自 System.Object ,因此您可以像将任何类型的对象强制转换为其派生类型一样容易地将intobject All this does is restrict what you are able to do with that object, because only the methods, fields, etc. of the base class are available. 所有这确实是限制你是什么能够与该对象 ,因为只有方法,字段的基类等可供选择。 Nothing special there. 没什么特别的。 But by casting an int to object , you change the way it's treated . 但是通过将intobject ,可以更改对它的处理方式 Just as by casting yourself in the theme park example to a "Person" -- something less specific than what you really are, a "New Yorker," or in other words a base type -- you changed the way you were treated. 正如铸造自己的主题公园为例,一个“人” -比你真的是,一个“纽约客”,不太具体,或者换句话说一个基本类型的东西-你改变的处理方式。

Does that make sense? 那有意义吗?


*Stating that reference types are "passed by reference" is arguably not a strictly accurate statement and has caused much confusion for many developers (a more accurate statement might be "references to reference types are passed by value"); *指出引用类型“通过引用传递”并不是严格准确的声明,并且对许多开发人员造成了很大的困惑(更准确的声明可能是“ 引用类型的引用通过值传递”); for a thorough discussion of this subject, you'll need to look elsewhere. 要对该主题进行全面讨论,您需要在其他地方查找。

1) Yes. 1)是的。 "int" is just an alias that C# defines for System.Int32. “ int”只是C#为System.Int32定义的别名。

2) Your first answer. 2)您的第一个答案。

3) string is the C# alias for the type System.String. 3)string是System.String类型的C#别名。 Since nearly everybody has "using System;" 由于几乎每个人都有“使用系统”; in their program, you can either use "string" or "String". 在他们的程序中,您可以使用“字符串”或“字符串”。

4) You can think of it as an int stored in a reference type box. 4)您可以将其视为存储在引用类型框中的整数。 Even though the type of the box is only visible as "object", the runtime knows that there's an int inside of it. 即使框的类型仅作为“对象”可见,运行时仍知道其中有一个int。

That's why you can't write: 这就是为什么你不能写:

int i = 10;
object x = i;
short j = (short) x; // this is an error because you can only unbox x as an int.

Much of this is in the C# language reference or in one of the introductory books. 其中大部分内容是在C#语言参考或一本入门书籍中。

1) int is an alias for the structure System.Int32. 1)int是System.Int32结构的别名。 You can define any alias you want for a type in C#. 您可以在C#中为类型定义任何别名。 For doing that you need to use an using statment similiar to the using statments you normally to import namespaces. 为此,您需要使用与通常用于导入名称空间的using语句相似的using语句。 For example, if I'd like to create an alias to System.Int64 and call it number, I'd write the following using statment at the beginning of my code file: 例如,如果我想为System.Int64创建一个别名并将其命名为number,我将在代码文件的开头使用statement编写以下内容:

using number = System.Int64;

Then, every time I use the alias number on my code the compiler and the intellisense will treat it exactly as System.Int64. 然后,每次我在代码上使用别名时,编译器和智能感知器都会将其完全视为System.Int64。

2) Use the default constructor of an System.Int32 is the same as assign 0 to an integer variable. 2)使用System的默认构造函数.Int32与将0分配给整数变量相同。

IComparable x = new System.Int32();

does exaclty the same as the code 确实与代码相同

IComparable x = 0;

It is possible to use the new operator with structures. 可以将new运算符与结构一起使用。 The semantics of the new to allocate the memory necessary for an object and invoke constructors. 的语义分配对象所需的内存并调用构造函数。 The diference between an object defined as a struct and an object defined as a class is how it is allocated. 定义为结构的对象与定义为类的对象之间的区别是如何分配对象。 Struct intances are allocated at the stack, whereas the class instances are allocated at heap. 结构实例在堆栈中分配,而类实例在堆中分配。

Some interesting fact is the in C# not everything derivates from object . 一个有趣的事实是,在C#中并非所有事物都源于object

3) string is keyword of C# compiler (as the int keyword) that is why you cannot see its definition using Reflector. 3) string是C#编译器的关键字(作为int关键字),这就是为什么您无法使用Reflector看到其定义的原因。 In fact, the IL code generated by the compiler doesn't even now the existance of those alias, because they are used only by the compiler during the compilation process. 实际上,编译器生成的IL代码现在甚至不存在那些别名,因为它们仅在编译过程中由编译器使用。 After the compilation all string references become a System.String in your compiled code. 编译后,所有字符串引用在您的已编译代码中都​​变为System.String。

4) The answer for this question is too long, so I suggest you to read the following article: Representation and Identity 4)这个问题的答案太长了,因此我建议您阅读以下文章: 表示法和身份

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM