编程基础—C# and .NET

以下问题由同事提问引发,或者在实际项目中遇到,这里总结一下。
问: C#中装箱和拆箱是指什么
答:
要明白装箱和拆箱,必须先明白其他一些东西。
C#纯面向对象,所有的东西都是对象;所有的数据类型和类等都是由基类System.Object继承而来的(只支持单一继承)(想想那张巨大的类关系图)。

根据在内存中如何被分配,C#中的类型一共分为两类,一类是值类型(Value Type),一类是引用类型(Reference Type)。值类型隐式地继承自System.ValueType类型,System.ValueType和所有的引用类型都继承自 System.Object基类。
值类型是在中分配内存,超出作用范围系统自动释放内存,跟C/C++中栈上一样。值类型主要包括整型(Sbyte、Byte、Char、Short、Ushort、Int、Uint、Long、Ulong), 浮点型(Float、Double), decimal, bool(前述值类型有固定大小) ,用户定义的结构(struct),枚举(enum)。它们都对应了类库中的类,如int是System. Int32的别名或者说是简写形式。
引用类型在托管堆中分配内存,初始化时默认为null,由垃圾回收机制回收。包括类、接口、委托、数组以及内置引用类型object与string。

由于C#中所有的值类型和引用类型都继承自System.Object,所以两者可以通过显式(或隐式)操作相互转换。栈上值类型的数据转换成托管堆上引用类型的数据,这一过程叫装箱(boxing);相反,托管堆上的引用类型的数据转换成栈上值类型的数据,这一过程叫拆箱(unboxing),被装过箱的对象才能被拆箱,且拆箱之后值类型必须跟装箱时的值类型匹配。
装箱(值类型到引用类型,栈到托管堆):用于在垃圾回收堆(即托管堆)中存储值类型。装箱是值类型到 object 类型或到此值类型所实现的任何接口类型的隐式转换。拆箱(引用类型到值类型,托管堆到栈):从 object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。
装箱拆箱

问:为什么会有装箱和拆箱,什么时候用到?
答:
性能,栈上的性能明显优于托管堆上的性能。装箱时,堆上申请空间耗资源,拷贝耗资源;拆箱,主要是拷贝耗资源。装箱比拆箱更耗资源,所以要尽量避免装箱。
栈上的值类型和装箱到托管堆上后的数据究竟有什么区别呢?托管堆上会多出一个类似于C++虚函数表指针的东西(方法表指针),通过它可以调用到基类的方法。
导致装箱的情况有:值类型转换成Object类型, 值类型转换成该值类型已实现的接口类型时, 当值类型调用Object类中未重写的方法时。代码示例如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace CSharp
{
    //define a value type A 
    struct A : ICloneable
    {
        public Int32 x;
        public override String ToString()
        {
            return String.Format("{0}", x); //boxing, value type "Int32" to referrence type "object"
        }
        public object Clone()
        {
            return MemberwiseClone();
        }       
    }

    class Program
    {
        static void Main(string[] args)
        {
            int i = 10;
            object ob = i;//boxing,这时会在托管堆上创建一块内存空间,并把a的值复制到该空间,并且创建System.Int类型的元数据信息相应的方法表等信息
            int i2 = (int)ob;// unboxing, 这句分两步,(int)ob是拆箱操作,返回一个ob的地址引用.(只有这步叫拆箱); 当赋值给i2时,会把地址引用的值复制给i2.(这步不是拆箱操作,但拆箱后往往跟随赋值,所以有些地方把这步包含在拆箱中.)

            A a = new A();  // stack for value type "struct A"
            a.x = 100;
            Object o = a; //boxing implicitly, to referrence type object
            Console.WriteLine(a.ToString()); //no-boxing, as <a> overrides the function ToString()
            Console.WriteLine(a.GetType());  //boxing implicitly, as it invokes GetType() of class object           

            ICloneable c = a;  //boxing implicitly, to referrence type Interface <ICloneable>
        }
    }
}

问: C#程序的编译和执行过程
答:
C#的源程序并不是被编译成二进制可执行形式,而是一种中间语言(IL),类似于JAVA字节码,称为中间代码(Microsoft Intermediate Language),然后通过 .NET Framework 的虚拟机(被称之为通用语言执行层(Common Language Runtime, CLR))执行。
Java的字节代码(Byte Code)和MSIL都是中间的汇编形式的语言,它们在运行时或其它的时候被编译成机器代码。在程序执行时,.Net Framework将中间代码翻译成为二进制机器码,从而使它得到正确的运行。最终的二进制代码被存储在一个缓冲区中。所以一旦程序使用了相同的代码,那么将会调用缓冲区中的版本。如果一个.Net程序第二次被运行,不需要中间码到二进制的翻译,速度很快。
当然C/C++进程中也可以调用C#实现的东西,windows debugger也可以对C#的程序进行调试,基本都是通过.NET CLR Core实现的;C#中也可以调用C/C++的函数。

问:C#编译时,如何查看中间代码MSIL
答:
Ildasm.exe 打开C#编译生成的.exe或.DLL文件查看中间代码。从中可以看到装箱等信息,对于分析性能等问题也是很有帮助的。
C#的编译器生成程序集包括中间语言模块和元数据,不能生成想过去C++编写的那样的本机代码,而中间语言模块的执行需要.NET Framework的支持,所以在目标机器上需要安装.NET Framework的。
csc.exe可执行文件通常位于系统目录下的 Microsoft.NET\Framework\Version 文件夹中。用于将.cs源代码文件编译生成MSIL中间代码。
Ildasm.exe 可以分析任何 .NET Framework .exe 或 .dll 程序集,并以可读的格式显示信息。Ildasm.exe 不只是显示 Microsoft 中间语言 (MSIL) 代码,它还显示命名空间和类型,包括其接口。如下图所示:
ILDSAM.exe查看中间代码

问: string使用的注意事项
答:
String是引用类型,其对象在托管堆上分配内存,由系统根据初始化字符串的大小自动分配内存。 使用不当,可能带来性能问题。当频繁地进行字符串操作(替换,添加,删除)时,优先使用System.Text.StringBuilder 类。如果下面的代码放到一个循环里面,可能带来严重的性能问题:

name += "xxx";

因为执行这行代码时,.NET CLR会在堆中创建一个新的字符串实例,给他分配足够的内存,然后存储合并的所有文本。然后更新存储在 name 变量中的内存地址,使变量正确的指向新的字符串对象。旧的字符串对象被销毁了引用,并等待系统回收。如果在循环中执行,每次都会申请新的空间,很耗资源。在真实的项目中,我们就曾犯过这个错误。

附录: 参考链接
C# 装箱和拆箱[整理]
http://www.cnblogs.com/huashanlin/archive/2007/05/16/749359.html
C# 指南之装箱与拆箱
http://www.cnblogs.com/hunts/archive/2007/01/19/boxing_unboxing.html

<

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C# 7 and .NET Core Cookbook by Dirk Strauss English | 25 Apr. 2017 | ASIN: B01N6QN9ZD | 628 Pages | AZW3 | 15.51 MB Key Features Easy-to-follow recipes to get you up-and-running with the new features of C# 7 and .NET Core 1.1 Practical solutions to assist you with microservices and serverless computing in C# Explore the new Visual Studio environment and write more secure code in it Book Description C# has recently been open-sourced and C# 7 comes with a host of new features for building powerful, cross-platform applications. This book will be your solution to some common programming problems that you come across with C# and will also help you get started with .NET Core 1.1. Through a recipe-based approach, this book will help you overcome common programming challenges and get your applications ready to face the modern world. We start by running you through new features in C# 7, such as tuples, pattern matching, and so on, giving you hands-on experience with them. Moving forward, you will work with generics and the OOP features in C#. You will then move on to more advanced topics, such as reactive extensions, Regex, code analyzers, and asynchronous programming. This book will also cover new, cross-platform .NET Core 1.1 features and teach you how to utilize .NET Core on macOS. Then, we will explore microservices as well as serverless computing and how these benefit modern developers. Finally, you will learn what you can do with Visual Studio 2017 to put mobile application development across multiple platforms within the reach of any developer. What you will learn Writing better and less code to achieve the same result as in previous versions of C# Working with analyzers in Visual Studio Working with files, streams, and serialization Writing high-performant code in C# and understanding multi-threading Demystifying the Rx library using Reactive extensions Exploring .Net Core 1.1 and ASP.NET MVC Securing your applications and learning new debugging techniques De

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值