csc.exe是C#的命令行编译器(CSharpCompiler),可以编译C#源程序成可执行程序。它与Visual Studio等IDE(Integrated Development Environment,集成开发环境)的区别是,csc.exe只是将用C#语言编写的源程序文件编译成.exe、.dll等文件,它只是一个编译器,而IDE提供丰富的调试、运行功能,提供很多view视图以及解决方案管理器等文件组织功能。

csc.exe包含在.NET Framework SDK(Software Development Kit)中,除了csc.exe外,SDK还包括其他语言的编译器,如vbc.exe(vb语言的编译器)以及其他一些可能会用到的工具、文档等。.NET Framework SDK在微软官网可以下载,但现在好像包含在了.NET Framework Developer Pack(开发者包)里。https://www.microsoft.com/net/download。在这里可以下载.NET Framework和.NET Core的最新版本及之前的版本。

如果不想那么麻烦,可以直接安装Visual Studio,.NET Framework SDK(或Developer Pack)是自动随着IDE的安装而安装的。可以在这里下载免费的Visual Studio 2017社区版:https://visualstudio.microsoft.com/zh-hans/downloads/,也可以在这个页面下方选择安装之前的旧版本。

安装好SDK后,在磁盘中会多出很多.NET开发工具,其中一些工具需要在命令提示符中打开(Command,CMD)。但这些工具分散在各个文件夹下,需要为它们配置PATH环境变量,这样很麻烦。在安装好Visual Studio后,磁盘中会多出一个类似于CMD的命令提示符,叫作Developer Command Prompt for VS + VS的版本号。Developer Command Prompt预先配置了每一个.NET开发工具,不需要为它们注册PATH路径,就可以在这里直接使用了。

比如这里,输入csc -?,窗口中显示了C#编译器的命令行参数列表;同样地,输入vbc -?,窗口显示VB编译器的命令行参数列表。其中,有些参数在我们用csc.exe编译C#源文件时会用到。


一、编辑源程序

  在C盘新建一个文件夹test,在文件夹里创建一个记事本文件HelloWorld.txt。用记事本打开编辑这个文件,输入C#代码,注意输入空格以缩进。之后将HelloWorld.txt后缀名改为HelloWorld.cs。*.cs是C#代码文件的后缀名。

  

二、打开Developer Command Prompt,启动csc.exe编译源程序

  更换路径到源程序所在文件夹下。

  

  输入csc HelloWorld.cs,启动编译。

  

  编译成功,在test文件夹下,可以看到HelloWorld.cs已经被编译成一个可执行程序HelloWorld.exe。

  

  

三、C#编译器(csc.exe)的输出选项

  前面已经实现了用记事本编辑C#源程序并用csc.exe编译,最后在文件夹下可以成功打开编译而来的可执行程序。现在,考虑编译过程中的一些细节。

  源程序叫作HelloWorld.cs,编译后的程序叫作HelloWorld.exe。看上去没什么问题,其实编译后的程序的名字和类型是可以通过C#编译器的输出选项(参数)指定的。

  ①/out 规定编译后文件名字,如果不进行设置,编译后文件名与源程序名字相同  ②/target:exe 编译源程序成可执行的控制台程序,缺省选项  ③/target:library 编译源程序成*.dll程序集  ④/target:winexe 编译源程序成窗体程序 (其中/target可缩写成/t)

  所以之前在编译时,我们输入:csc HelloWorld.cs其实等价于输入:csc /target:exe /out:HelloWorld.exe HelloWorld.cs,只是中间两个选项都省略掉了。命令行选项和源文件的顺序是任意的,可以命令行选项在前,源文件在后。也可以源文件在前,命令行选项在后,甚至可以这样写:csc /target:exe HelloWorld.cs /out:HelloWorld.exe,这些都是可以的。

  打开Developer Command Prompt,进行其他选项的测试。

  

  此外,命令行输出选项中的"/"符号还可以换成"-"符号。

  

四、源程序中引用了外部程序集

  修改源文件。using System.Windows.Forms引入了一个命名空间,以使用其中的MessageBox类的静态方法Show(),弹出一个对话框显示相关内容。System.Windows.Forms命名空间存在于System.Windows.Forms.dll程序集中(命名空间与程序集名称相同)。源文件中使用了外部程序集的内容,csc.exe在编译时需要通过/reference命令行选项指定引用的外部程序集(/reference可缩写为/r)。

  

  下面进行编译,省略/target和/out选项。

  

  

  可能有读者在这里并没有/reference:System.Windows.Forms,而是直接csc HelloWorld.cs,也可以成功编译并运行,在后文会对这个问题进行解答。(C#默认响应文件csc.rsp的概念)

  这里还有一个问题,在源文件中,使用System.Windows.Forms命名空间中的MessageBox类,需要引入这个命名空间所在的程序集System.Windows.Forms.dll,那使用System命名空间中的Console类,为什么不引入System命名空间所在的程序集System.dll?

  这就涉及到了“外部程序集”中“外部”的概念。在Visual Studio中,引入System.Windows.Forms.dll程序集后,查看其包含的内容。可以看到Show()方法是MessageBox类的静态方法,MessageBox类是System.Windows.Forms命名空间中的成员,而这个命名空间又是System.Windows.Forms.dll程序集中的逻辑概念。下图中,左侧两个小黑方块中间用一杠连起来的那个符号就是程序集的符号,花括号的那个符号是命名空间的意思。

  

  System.Windows.Forms.dll是外部程序集,那什么又叫作“不是外部程序集”呢?查看System.dll程序集中的System命名空间的成员,发现并没有我们使用的Console类。

  

  这是因为,我们使用的Console.WriteLine()中的Console类所在的命名空间System,不是包含在System.dll中的!我们查看mscorlib这个程序集。

  

  Console类原来是mscorlib.dll程序集中System命名空间的成员。mscorlib(MicroSoft CORe LIBrary),相对于System.Windows.Forms等一些外部程序集来说,是.NET平台中核心的程序集,可以把它们理解成“内部的”程序集。所以回到之前的那个问题,使用mscorlib.dll程序集中命名空间中的成员,只要在源文件中使用using关键字引入所用成员所在的命名空间即可(也可使用成员的完全限定名),而不用在使用csc.exe编译时通过/reference命令行选项额外引入mscorlib.dll这个程序集。

  其实,在Visual Studio IDE里看这个问题,也是相通的。在我们新建了一个控制台应用程序后,在解决方案管理器中References下会自动引入一些外部程序集。(mscorlib不显示在其中,因为它不需要引入!)当需要使用MessageBox等一些没有自动被引入的外部程序集中的成员时,就需要我们手动右键References添加所用的程序集。而mscorlib.dll是在创建应用程序时就已经添加进来的程序集,不用额外引入。在IDE中是这样,在命令行提示符中使用csc.exe编译时也是这样。

  在Visual Studio中可以看到程序集在磁盘中的路径。

  

  在Visual Studio中创建应用程序时会选择.NET Framework的版本,因为例子中这个程序选择的是.NET Framework 4.6.1,所以它引用的程序集就是磁盘中.NET Framework 4.6.1中的程序集。

  

  

  进入这个文件夹,可以看到其中包含的程序集。我们看到mscorlib.dll这个程序集的容量很大,也反映出这个程序集的重要性。

  

  如果csc.exe需要引入多个外部程序集,在/reference:程序集1;程序集2 中用英文分号";"分隔即可。

五、编译多个源文件

  现在我们已经可以使用csc.exe和记事本构建一个可以引用外部程序集的控制台应用程序了,但是我们所有的代码都是写在一个C#源文件中的。我们也可以将代码写在多个文件中,使用csc.exe对多个源文件进行编译。

  在test文件夹下增加MyMessageBox.txt文件,之后要将后缀名改为.cs(下同)。

  

  修改HelloWorld.txt文件。

  

  打开Developer Command Prompt,编译这两个文件,注意依然要使用/reference引入使用的外部程序集。编译的多个文件之间用空格隔开。

  

  执行这个程序。

  

  此外,在使用csc.exe编译多个文件时,还可以使用通配符"*"表示编译当前目录下的所有指定后缀名文件。如:csc *.cs表示编译当前目录下所有.cs文件。

六、使用C#响应文件

  至此,我们已经可以使用csc.exe编译多个源文件的C#应用程序了。在编译过程中,需要设置一些命令行选项以达到某种效果。当程序规模大到一定程度,就需要输入很多的命令行选项,容易出错且录入工作量大。为了应对这一问题,C#有响应文件(response file,后缀名为rsp)的概念。C#响应文件包含编译一个或多个C#源文件时需要指定的命令行选项。

  编辑HelloWorld.rsp文件,将编译源文件时需要用到的引入外部程序集、设置输出程序的类型及名字等命令行选项写在这个文件里,并将这个响应文件和源程序文件放在同一目录下。csc.exe编译时,输入csc @HelloWorld.rsp就可以按照设置的命令行选项编译这个C#源程序了。

  

  

  程序可以正常运行。

  

  这里有几点需要注意的地方:①写在后面的命令行选项或响应文件的内容会覆盖掉前面的命令行选项或响应文件的内容(以后规定的为准!) ②/reference具有累加性,最终程序引用的外部程序集为各个地方(命令行选项和响应文件)规定的程序集的并集

七、关于C#默认的响应文件csc.rsp

  回到之前提到的那个问题,为什么即使没有使用/reference引入需要的外部程序集,程序也是可以成功编译并执行的?

  C#编译器(csc.exe)有一个与之关联的默认响应文件(csc.rsp),csc.rsp与csc.exe在同一目录下(我没有找到..)。在编译C#源程序时,无论有没有自己编写的响应文件,这个默认的响应文件csc.rsp都会执行。而csc.rsp已经写好了对很多核心程序集的引用(用/reference或/r命令行选项)。所以即使我们没有使用/reference引入外部程序集,csc.rsp也帮我们引入好了。

  如果不想在编译时自动执行csc.rsp,可以指定/noconfig选项。

  如果我们在编译时指定了/noconfig选项且没有使用/reference引入源文件中需要的外部程序集,那么编译将报错。

  

  如果程序引用了在源文件中没有用到的外部程序集(比如csc.rsp帮我们自动引入的),它们将会被编译器忽略,所以不会影响程序的质量。


返回目录:C#学习笔记

[C#学习笔记1]用csc.exe和记事本写一个C#应用程序的更多相关文章

  1. SpringBoot学习笔记(11):使用WebSocket构建交互式Web应用程序

    SpringBoot学习笔记(11):使用WebSocket构建交互式Web应用程序 快速开始 本指南将引导您完成创建“hello world”应用程序的过程,该应用程序在浏览器和服务器之间来回发送消 ...

  2. 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(下)

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  3. 一起学习造轮子(二):从零开始写一个Redux

    本文是一起学习造轮子系列的第二篇,本篇我们将从零开始写一个小巧完整的Redux,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Promises/A+,Red ...

  4. 一起学习造轮子(一):从零开始写一个符合Promises/A+规范的promise

    本文是一起学习造轮子系列的第一篇,本篇我们将从零开始写一个符合Promises/A+规范的promise,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Pr ...

  5. 一起学习造轮子(三):从零开始写一个React-Redux

    本文是一起学习造轮子系列的第三篇,本篇我们将从零开始写一个React-Redux,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Promises/A+,Re ...

  6. python学习(10)字典学习,写一个三级菜单程序

    学习了字典的应用.按老师的要求写一个三级菜单程序. 三级菜单程序需求如下: 1.深圳市的区--街道--社区---小区4级 2.建立一个字典,把各级区域都装进字典里 3.用户可以从1级进入2级再进入3级 ...

  7. 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(中)

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 四.创建一个Blazor应用程序 1. 第一种创 ...

  8. 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(完)

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  9. Python学习笔记:PyInstaller(exe程序打包)

    PyInstaller可以将Python程序打包成一个exe程序来独立运行,用户使用时只需要执行这个exe文件即可,不需要在机器上再安装Python及其他包就可运行了.另外,PyInstaller相较 ...

随机推荐

  1. JavaScript对象类型判断注意点

    注意点 不要使用 new Number() . new Boolean() . new String() 创建包装对象:用 parseInt() 或 parseFloat() 来转换任意类型到numb ...

  2. Android屏幕适配讲解与实战

    文章大纲 一.屏幕适配是什么二. 重要概念讲解三.屏幕适配实战四.项目源码下载   一.屏幕适配是什么   Android中屏幕适配就是通过对尺寸单位.图片.文字.布局这四种类型的资源进行合理的设计和 ...

  3. javascript中apply、call和bind的区别及方法详解

    文章目录   apply.call apply.call 区别 apply.call实例 数组之间追加 获取数组中的最大值和最小值 验证是否是数组(前提是toString()方法没有被重写过) 类(伪 ...

  4. Xapian索引-文档检索过程分析之匹配百分比

    本文属于文档检索过程分析的一部分,重点分析文档匹配百分比(percent)的计算过程. 1 percent是什么? 我们之前分析的检索demo: Xapian::Query term_one = Xa ...

  5. Ubuntu 安装phpMyAdmin + 配置nginx

    0x01 安装phpMyAdmin ``` sudo apt-get install phpmyadmin ``` 0x02 添加链接 ``` sudo ln -s /usr/share/phpMyA ...

  6. 【python3基础】相对路径,‘/’,‘./’,‘../’

    python3相对路径 “/” 前有没有 “.” ,有几个“.”,意思完全不一样. “/”:表示根目录,在windows系统下表示某个盘的根目录,如“E:\”: “./”:表示当前目录:(表示当前目录 ...

  7. 微服务实战(三):落地微服务架构到直销系统(构建基于RabbitMq的消息总线)

    从前面文章可以看出,消息总线是EDA(事件驱动架构)与微服务架构的核心部件,没有消息总线,就无法很好的实现微服务之间的解耦与通讯.通常我们可以利用现有成熟的消息代理产品或云平台提供的消息服务来构建自己 ...

  8. Spring Boot 中的静态资源到底要放在哪里?

    当我们使用 SpringMVC 框架时,静态资源会被拦截,需要添加额外配置,之前老有小伙伴在微信上问松哥Spring Boot 中的静态资源加载问题:"松哥,我的HTML页面好像没有样式?& ...

  9. 知识小罐头07(tomcat8请求源码分析 下)

    感觉最近想偷懒了,哎,强迫自己也要写点东西,偷懒可是会上瘾的,嘿嘿!一有写博客的想法要赶紧行动起来,养成良好的习惯. ok,继续上一篇所说的一些东西,上一篇说到Connector包装了那两个对象,最后 ...

  10. springboot~rabbitmq自己通过UI手动发布队列需要注意的地方

    springboot里发布队列消息 为了兼容性和可读性更好,我们一般使用json字符串做为数据载体. public void decreaseCallMonitor(CallMonitorInfo c ...