多文件程序集构建学习的心得(针对可执行程序集初步学习的小结)
今天主要初步学习了.NET框架和.NET命名空间及程序集,特别对单文件程序集、多文件程序集、在IDE中学用“添加引用”这三方面做了实验,在IDE里添加引用比较简单,但用al命令创建程序集,却遇到了困难,因为总是遇到“ error AL1037:无法找到入口点方法”这个故障,在网上找了很久,也没找到解决的办法,很是奇怪,按照MSDN和书上的参数说明去做,为什么总是报故障,经过琢磨,终于解决了,也对多文件程序集有了进一步认识。
现在只对多文件的exe可执行程序集有了一定的了解,具体如下:
1、针对多文件,一定要先将各托管代码文件其编译为模块(用csc命令编译),如:csc /t:module B.cs(使用 /t: 编译器选项指定 module 参数,表明文件应作为模块(而不是作为程序集)编译。编译器生成名为 B.netmodule 的模块,该模块可添加到程序集。)
(MSDN里内容:将包含程序集中其他模块引用的命名空间的所有文件编译成代码模块。代码模块的默认扩展名为 .netmodule。例如,如果名为 Stringer 的文件创建名为 myStringer 的命名空间(在 Client 文件代码中引用),则应先将 Stringer 编译成代码模块。)
2、当出现下述情况:A托管代码文件中引用了B托管代码文件的命名空间,将A编译为模块时,一定要使用/addmodule选项: /addmodule:B文件的模块文件名。如:csc /addmodule:B.netmodule /t:module A.cs
(MSDN里的内容:编译所有其他模块,使用必要的编译器选项来表明代码中引用的其他模块,即必须编译包含对其他模块的引用的模块。)
3、C#编译器支持使用以下两种不同语法直接创建多文件程序集。创建多文件程序集(其实单文件程序集也可以这样创建)有两种方法
1)两次编译创建出一个双文件程序集:
csc /t:module B.cs
csc A.cs /addmodule:B.netmodule
2)一次编译创建出一个双文件程序集:
csc /out:A.exe A.cs /out:B.netmodule B.cs
也可写成:csc /t:exe /out:A.exe A.cs /t:module b.cs (其中/out:A.exe也可不写)
4、C#还是推荐用al命令即程序集链接器 (Al.exe) 从一组编译的代码模块中创建程序集。
MSDN中是这样描述的:
使用“程序集链接器”创建多文件程序集,
使用程序集链接器 (Al.exe) 来创建包含程序集清单的输出文件。此文件包含作为程序集组成部分的所有模块或资源的参考信息。
在命令提示处,键入下列命令:
al <module name> <module name> … /main:<method name> /out:<file name> /target:<assembly file type>
在此命令中,“模块名”参数指定程序集要包含的各模块的名称。/main: 选项指定作为程序集入口点的方法名称。/out: 选项指定输出文件的名称,它包含程序集元数据。/target: 选项指定程序集是控制台应用程序可执行文件 (.exe)、Windows 可执行文件 (.win) 或库文件 (.lib)。
针对A、B两个已生成好的模块,al命令操作如下:
al a.netmodule b.netmodule /main:<method name> /out:<file name> /target:<assembly file type>
5、举个例子
1)代码文件内容
B.cs文件内容:
using System;
using System.Collections.Generic;
using System.Text;
namespace StringShowLibrary
{
public class StringShow
{
string strVar;
public StringShow(string _str)
{
strVar = _str;
}
public string GetStr()
{
return strVar;
}
}
}
A.cs文件内容:
using System;
using System.Collections.Generic;
using System.Text;
using StringShowLibrary;
namespace Program
{
class ProgramClass
{
static void Main()
{
StringShow st1 = new StringShow("hello world!");
Console.WriteLine(st1.GetStr());
Console.ReadLine();
}
}
}
包含程序集标题和版本信息的info.cs文件内容:
using System;
using System.Reflection;
[assembly:AssemblyTitle("365UP")]
[assembly:AssemblyVersion("1.0.0.1")]
2)编译成模块
先将a.cs和b.cs、info.cs都编译成模块,注意编译时选项不同
csc /t:module b.cs 生成了b.netmodule
csc /addmodule:b.netmodule /t:module a.cs 生成了a.netmodule
csc /t:module info.cs 生成了info.netmodule
注意:csc中的输入是不区分大小写的
3)如果只用csc构建多文件程序集,是可以不用编译模块或者至少不用编译a,cs为模块的
a、多步骤构建
csc /t:module B.cs
csc /t:module info.cs
csc A.cs /addmodule:B.netmodule;info.netmodule (当要将多个模块作为元数据导入程序集时,addmodule选项后面的模块文件名用“;”隔开)
但上句的实现并不能把info模块中的信息编译到程序集中。目前我只得用“csc A.cs /addmodule:b.netmodule /t:module info.cs”来实现
b、一步骤构建
csc /t:exe /out:A.exe A.cs /t:module b.cs /t:module info.cs 或者下句
csc /out:2.exe A.cs /out:b.netmodule b.cs /out:info.netmodule info.cs
都可以!
4)如果用al构建多文件程序集(接第2)步)
al a.netmodule b.netmodule info.netmodule /out:1.exe /t:exe /main:Program.ProgramClass.Main
要注意的是:在al中的/main:选项后一定要将程序集入口点的方法名称所在的类和命名空间(如果有命名空间)都写出来!而且区分大小写!
但即使这样还是发现编译程序会报:“ 签名或可见性不正确或者“Program.ProgramClass.Main”是泛型,因此它不能是入口点”的错误
原因是static void Main()默认是private访问修饰符,用al命令构建多文件程序集必须将此处改为internal或public,改后重新编译模块,和用al构建,成功!