上一章博客我为你们介绍了Process类的全部基本使用方法,这一章博客我来为你们作一个小扩展,来熟悉一下Process类的实际使用,废话很少说咱们开始演示。c#
先看看咱们的软件要设计成的布局吧。多线程
首先咱们须要给定会使用到的dll,记得vs中的引用那一项吗?咱们虽然不须要将这里面的引用所有导入进来,可是咱们须要将咱们使用过的dll所有导入进来,否则编译时会提示找不到类方法之类的。异步
可能有些同窗不知道怎么查看一个类或者方法所在的dll,其实只用对着那个方法或者类按下f12就能在打开的文档的正上方看到所在的dll了,包括dll所在的路径都写的很是清楚。async
我后续更新是想完成导入工程,读取出来工程内的cs文件和资源,选择须要编译的cs文件和资源,而后点击编译,完成编译,不过功能比较多,我会慢慢的更新,没更新一个版本会在本博客的下方附上地址。布局
介绍就先到此为止,咱们开始讲解代码的实现过程,因为整个工程的代码大部分和咱们须要讲解的内容无关,因此我只挑出核心功能在这里介绍一下,其余的内容请自行下载工程查看。先贴上代码,我感受代码中的注释已经写的很是明白的,不过我仍是找些注释解释的不是很明白的地方详细讲解下。ui
/// <summary> /// 异步执行编译 /// </summary> private async void Compiled() { //注意:咱们下面这几个变量提早拿出来是由于ui都式不能跨线程访问,异步操做也会被认为是多线程。 //dll的输出路径 string working = path_textBox.Text; //dll的名字 string name = name_textBox.Text; //vs的路径,这里咱们使用的是vs的一个批处理文件进行dll的编译,它会自动帮咱们配置好环境,虽然咱们直接使用.net的csc.exe也能编译,可是你看个人代码里用的c#6.0的各类新语法都是须要编译器支持的,仅仅使用.net的csc.exe是没法完成编译的 string vs_Path = vs_Path_textBox.Text + "\\Common7\\Tools\\VsMSBuildCmd.bat"; //这个也不算新语法了,这个和上面的async是一对,你给一个方法标记上async表示这个方法是异步的,可是注意await等待的代码之外的代码是同步执行的,也就是说是主线程执行的,必须将须要执行的代码放在Task.Run()中,才会异步执行,我一开始就是有这个误区一直疑惑异步为啥还会卡。 await Task.Run(() => { //建立一个ProcessStartInfo,设置初始信息 System.Diagnostics.ProcessStartInfo start = new System.Diagnostics.ProcessStartInfo("cmd.exe"); //让应用能够接受输入,这里咱们用于向控制台输入命令 start.RedirectStandardInput = true; //让应用能够输出数据,这里咱们是打算读取在编译完毕后读取控制台的输出数据判断是否编译成功的,可是暂时没法完成此功能 start.RedirectStandardOutput = true; //这个属性设置成true可让打开的控制台无窗口,以达到咱们想要的效果 start.CreateNoWindow = true; //这个属性也不知道干什么用的,可是你想对控制台进行控制,这个属性必须设置为false,否则会抛出异常告诉你,必需要将此属性设置为false start.UseShellExecute = false; //终于开始正题了,就像上一章博客介绍的那样,咱们经过ProcessStartInfo初始化一个Process对象 System.Diagnostics.Process process = System.Diagnostics.Process.Start(start); //如下就是像控制台输入命令的过程了,想从控制台读取数据,就直接调用StandardOutput.ReadLine();就能读取一行了,不过要注意了,你调用了此方法后,控制台会一直等待一个输入,因此很容易就一直卡在那里不执行下面的代码 //GetLetter方法是我本身定义个获取路径中的盘符加上:用的,用此方法获取到vs所在的盘,以后直接将命令输给cmd,就能进入vs所在的磁盘分区了,不明白的本身去补控制台命令 process.StandardInput.WriteLine(GetLetter(vs_Path)); //用cd命令进入VsMSBuildCmd.bat批处理文件所在的路径 process.StandardInput.WriteLine("cd " + System.IO.Path.GetDirectoryName(vs_Path)); //获取VsMSBuildCmd.bat文件的名字,并输入给cmd,执行这个批处理文件的命令 process.StandardInput.WriteLine(System.IO.Path.GetFileName(vs_Path)); //批处理文件执行完毕后,咱们的控制台环境就被搭建好了,咱们将路径再转向dll的输出目录 process.StandardInput.WriteLine(GetLetter(working)); process.StandardInput.WriteLine("cd " + working); //将会使用到的dll以","为分割符拼接起来。这里我说明一下会使用到的dll什么意思,假设咱们的类调用第三方dll之类的时候,固然你调用了如System.Windows.MessageBox();之类的方法也须要引用对应的dll。
//不知道用的方法或者类是在哪一个dll?对着你的方法或者类按下f12在代开的文档的最上方写着呢。 //StringBuilder是个高效的字符串拼接类,可是相应的功能没有string多,在拼接完全部字符串后,直接ToString就能获得字符串 StringBuilder dll = new StringBuilder(); foreach (string item in DllPath) { dll.Append(item); dll.Append(","); } //将须要编译的cs文件以空格为分隔符拼接起来,这里用空格,dll那里用,这是语法,别问我为何。 StringBuilder cs = new StringBuilder(); foreach (string item in CsPath) { cs.Append(item); cs.Append(" "); } //若是没有使用其余dll的状况下 if (dll.ToString() == "") { //因为没有使用dll的状况。 //我一一解释这些命令都是干吗用的,csc是用来编译咱们cs文件的应用程序,/t:library表明咱们要将cs文件编译成dll,固然也能编译成exe之类的,以后跟上空格再加上全部须要编译的cs文件。再以后用/out:指定输出的名字 process.StandardInput.WriteLine($"csc /t:library {cs.ToString()} /out:{name}"); } else { //使用了其余dll的状况下,其余的都跟上面相同。主要式添加了/r:,/r:后面跟上全部的dll,用","分割 process.StandardInput.WriteLine($"csc /r:{dll.ToString()} /t:library {cs.ToString()} /out:{name}"); } //全部命令都执行完毕了,接下来久给一个exit的命令退出控制台吧 process.StandardInput.WriteLine("exit"); //等待控制台关闭 process.WaitForExit(); //释放Process对象的全部资源 process.Close(); //执行事件,这里有个新语法,?.表示CompiledEndEvent不为null的状况下就出发CompiledEndEvent事件 CompiledEndEvent?.Invoke(); }); }
string vs_Path = vs_Path_textBox.Text + "\\Common7\\Tools\\VsMSBuildCmd.bat";
咱们先说明一下VsMSBuildCmd.bat这个批处理文件吧,vs2013和vs2015我均已证明VsMSBuildCmd.bat所在路径是vs安装路径下的一指定路径下的,所以我这里久干脆拼接了一下字符串。若是低版本vs路径有所不一样各位能够看着修改。VsMSBuildCmd.bat文件帮咱们作了一些编译操做,不执行这个文件,而是直接执行.net目录下的csc.exe的话,咱们是没法编译c#的一些新语法的。有一点各位要明白,c#版本和.net版本几乎没有太大关系,也不能说彻底不要紧,c#新版本的语法实际上是编译器维护的,因此咱们仅仅用csc.exe是没法识别那些新语法的。spa
再简单介绍一些async和await,这个是c#5.0增长的两个关键字,他让咱们编写异步方法变得异常方法,经过上面的代码你也能够看到这个方法是能够混合异步和同步操做的,咱们能够在方法中使用await等待一个费时的操做,在这个操做执行完毕后才会继续执行下面的方法,且不堵塞线程。仅仅只有Task.Run();中的方法是异步执行的,这样极大的方便了咱们不少的操做。用法我已经告诉你们了,怎么去利用各自看着用吧。对了,别在Unity中使用,Unity中用的是c#4.0的语法和.Net2.0的版本,没法支持这两个关键字。.net
其余的没啥好讲的了,注释写的已经很是清楚了。我就给各位讲讲本代码中使用到的c#6.0的新语法吧。线程
首先是"$"运算符,这个运算符是为了简化string.Format();方法而被设计出来的,我给个$运算符和string.Format的例子一对比,你就会简单明了的明吧$干什么用的,怎么用了。设计
string a = "我", b = "是", c = "谁", d = "?"; string s = $"{a}到底{b}{c}呀{d}"; string s2 = string.Format("{0]到底{1}{2}呀{3}", a, b, c, d);
看着上面的例子,两种拼接字符串的方式,用$运算符能够下降咱们很多工做量,并且阅读性也增长了。他们的输出结果天然也是相同的。
而后式?.运算符,中文名叫什么来着忘记了,不过也不用在乎这种事。这个运算符依然是简化咱们的工做用的,看下面的代码,这样很容易就能明白。
LL kk = null; //咱们之前的写法 if (kk != null) kk.S(); //而用?.运算符,这个运算符意思就是若是kk不为null的话就执行kk.S();跟上面那两行代码一个功能 kk?.S();
说到?.运算符了,就不得不提提??运算符,?.运算符表示不为null时执行,??运算符则表示为null时执行。看段代码:
LL kk = null; //咱们之前的写法 if (kk == null) kk = new LL(); //而用?.运算符 kk = kk ?? new LL();
好了,感谢阅读本篇博客,但愿各位也能有所收获。Process类和ProcessStartInfo类还有不少功能,你们能够本身去多多研究研究,有机会的话我会在后续章节中为各位继续分享。
附上整个工程源码,工程是vs2015写成的WPF程序,使用了大量c#6.0的新语法,低版本的打开会提示大量的错误,vs2013貌似能正常编译,没试过,再低版本的都没法使用。不过只用将工程中的几个不兼容的小错误修改一下就能正常编译了。
若是你只是想要运行程序的话,直接在工程目录中的bin\Release目录下找到DLL编译器.exe便可拷贝走使用。
工程还有不少问题,好比没法获取编译结果,不会储存最近一次的操做信息登,这些问题我都会后续修复,并在此页面更新,每修改一版我都会写上版本。
1.0 beta版:http://files.cnblogs.com/files/menghuijinxi/DLL%E7%BC%96%E8%AF%91%E5%99%A8.zip
文章原创,欢迎转载,请标明出处。