上一篇文章中说了命名空间,你猜猜接下来该说啥。是了,命名空间下面就是类型,知道了如何生成命名空间的定义代码,以后就该学会如何声明类型了。c#
CLR的类型一般有这么几种:类、接口、结构、枚举、委托。是这么几个,应该没有漏掉的吧。ide
定义类型,除了委托外均可以用 CodeTypeDeclaration 类完成。CodeNamespace类公开一个Types集合,定义的类型必须添加到这个集合中,才能与命名空间关联。spa
举个例子,下面代码将定义一个叫 Mouse 的类。code
// 编译单元 CodeCompileUnit unit = new CodeCompileUnit(); // 命名空间 CodeNamespace nspace = new CodeNamespace(); nspace.Name = "Sample"; unit.Namespaces.Add(nspace); // 类声明 CodeTypeDeclaration clsdcl = new CodeTypeDeclaration(); clsdcl.Name = "Mouse"; // 公共且密封,不让继承 clsdcl.TypeAttributes = System.Reflection.TypeAttributes.Sealed | System.Reflection.TypeAttributes.Public; // 加入类型集合中 nspace.Types.Add(clsdcl); CodeDomProvider prd = CodeDomProvider.CreateProvider("cs"); prd.GenerateCodeFromCompileUnit(unit, Console.Out, null);
不须要显式把 IsClass 说罢为 true,由于默认就是生成类(class)的。这里有一点老周要说明一下。对象
描述类型的可访问性有两个属性能够用,一个是从 CodeTypeMember 类继承的 Attributes,因为MemberAttributes枚举不能进行组合运用(我想把类定义为 public sealed),因而我就选用了TypeAttributes,它用的值是反射里面的TypeAttributes枚举,这个枚举能够多个值组合运用。blog
生成的代码以下图所示。继承
下面代码将定义一个名为 Point 的结构。接口
CodeTypeDeclaration strdcl = new CodeTypeDeclaration("Point"); strdcl.IsStruct = true; strdcl.TypeAttributes = System.Reflection.TypeAttributes.NotPublic; nspace.Types.Add(strdcl);
NotPublic表示类型可访问性为internal,即仅限当前程序集可见。生成代码以下图所示。字符串
知道怎么定义类和结构后,那么枚举就难不倒你了。string
CodeTypeDeclaration endcl = new CodeTypeDeclaration("AccessType"); endcl.IsEnum = true; nspace.Types.Add(endcl);
生成代码以下。
可是,大伙伴们必定会问,那委托呢。CodeTypeDeclaration类并不能用来声明委托类型,但它派生出了一个CodeTypeDelegate类,它是定义委托类型专业户。
咱们知道,委托相似于方法,那么你想一想,委托类型须要几个要素。首先,参数列表要吧。而后,还得有个返回值。好,仍是实际效果有用,很少说,来,先定义一个委托类型试试手。
CodeCompileUnit unit = new CodeCompileUnit(); CodeNamespace ns = new CodeNamespace("Calculators"); unit.Namespaces.Add(ns); CodeTypeDelegate dl = new CodeTypeDelegate("OnAdd"); // 返值为int类型 dl.ReturnType = new CodeTypeReference(typeof(int)); // 两个参数 CodeParameterDeclarationExpression p1 = new CodeParameterDeclarationExpression(); p1.Name = "x"; p1.Type = new CodeTypeReference(typeof(int)); CodeParameterDeclarationExpression p2 = new CodeParameterDeclarationExpression(); p2.Name = "y"; p2.Type = new CodeTypeReference(typeof(int)); dl.Parameters.Add(p1); dl.Parameters.Add(p2); ns.Types.Add(dl);
CodeTypeReference用于生成类型引用代码,能够用Type对象提供类型信息,也能够用字符串来提供。方法参数能够用CodeParameterDeclarationExpression类来声明,核心元素是参数类型与参数名。
若是委托没有参数,就不用向Parameters集合添加任何东西,有几个参数就加几个。
最后生成的委托类型代码以下。
下面代码生成一个无参数并返回void的委托类型。
CodeTypeDelegate dl2 = new CodeTypeDelegate("DoWork"); dl2.ReturnType = new CodeTypeReference(typeof(void)); ns.Types.Add(dl2);
生成的委托类型为
============================================
此时你们可能会想到,类型之间存在继承关系,好比类与类之间,类/结构能够实现接口。
下面代码声明了两个类——A、B,其中B从A派生。
CodeCompileUnit unit = new CodeCompileUnit(); CodeNamespace ns = new CodeNamespace("Samples"); unit.Namespaces.Add(ns); CodeTypeDeclaration t1 = new CodeTypeDeclaration("A"); CodeTypeDeclaration t2 = new CodeTypeDeclaration("B"); // B 从 A 派生 t2.BaseTypes.Add(new CodeTypeReference(t1.Name)); ns.Types.AddRange(new CodeTypeDeclaration[] { t1, t2 });
CodeTypeDeclaration 类有一个 BaseTypes 集合,用来设置该类型的基类。
这里你必须一个问题:虽然 BaseTypes 是一个集合,能够添加N个类型引用,但是你得遵照.NET的面向对象规则,即类不能多继承,但类型能够实现多个接口。
尽管你能够这么搞:
t2.BaseTypes.Add(new CodeTypeReference(t1.Name)); t2.BaseTypes.Add(new CodeTypeReference(typeof(string)));
而后还生成了这样的代码
然而,你就要想想了,这样的代码可否经过编译,不兴趣的朋友不妨试试。
想试试吗,好,老周就献丑了,列位看官莫笑。
CodeDomProvider prd = CodeDomProvider.CreateProvider("c#"); // 生成代码 prd.GenerateCodeFromCompileUnit(unit, Console.Out, null); CompilerParameters options = new CompilerParameters(); // 输出文件 options.OutputAssembly = "test.dll"; // 引用的程序集 options.ReferencedAssemblies.Add("System.dll"); // 开始编译 CompilerResults res = prd.CompileAssemblyFromDom(options, unit); // 200% 出错 if (res.Errors.Count == 0) { Console.WriteLine("编译完成。"); Console.WriteLine($"输出程序集:{res.CompiledAssembly.Location}"); } else { foreach (CompilerError er in res.Errors) { Console.WriteLine($"{er.ErrorNumber} - {er.ErrorText}"); } }
而后,一编译,就有好戏看了。
这告诉你,类A的基类不能有多个类。
下面再看看如何实现多个接口。
CodeCompileUnit unit = new CodeCompileUnit(); CodeNamespace ns = new CodeNamespace("Commons"); unit.Namespaces.Add(ns); // 这两个都是接口 CodeTypeDeclaration t1 = new CodeTypeDeclaration("IBall"); t1.IsInterface = true; CodeTypeDeclaration t2 = new CodeTypeDeclaration("IPlayer"); t2.IsInterface = true; ns.Types.Add(t1); ns.Types.Add(t2); // 这个是类,实现上面两个接口 CodeTypeDeclaration t3 = new CodeTypeDeclaration("FootballPlayer"); t3.BaseTypes.Add(new CodeTypeReference(t1.Name)); t3.BaseTypes.Add(new CodeTypeReference(t2.Name)); ns.Types.Add(t3);
t1和t2都是接口类型,t3是类,它将实现前面两个接口。运行后会生成如下代码。
OK,对于类型定义,今天就讲这么多吧。顺着这个层次,下一篇文章,老周就会说说类型成员的定义。
开饭了,开饭了……