考虑以下代码示例(LINQPad中的copy-pastable):
void Main()
{
var ttNamespace = new CodeNamespace("SampleNamespace");
ttNamespace.Imports.AddRange(new[]{"System", "System.Text", "System.Threading"}.Select(x => new CodeNamespaceImport(x)).ToArray());
var newType = new CodeTypeDeclaration("SampleClass")
{
TypeAttributes = TypeAttributes.Public
};
var newField = new CodeMemberField(typeof(List<int>), "_field")
{
Attributes = MemberAttributes.Public
};
newField.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference(typeof(List<int>)), new CodeExpression[] { });
newType.Members.Add(newField);
ttNamespace.Types.Add(newType);
var parameters = new CompilerParameters()
{
GenerateExecutable = false,
OutputAssembly = @"C:\test.dll"
};
var ccUnit = new CodeCompileUnit();
ccUnit.Namespaces.Add(ttNamespace);
var result = CodeDomProvider.CreateProvider("C#").CompileAssemblyFromDom(parameters, ccUnit);
Console.WriteLine (result.Errors);
}
如您所见,我明确添加了名称空间System
,System.Text
和System.Threading
。我还使用了List<int>
类型,但没有为System.Collections.Generic
提供名称空间导入。
从逻辑上讲,这应该会在某处产生错误。也许不是在编译时,但绝对是在运行时。但情况并非如此,代码编译为:
我们可以看到已经为我们组织了所有using
语句:省略了多余的语句,并添加了必需的语句。显然这非常有用,但这引出了一个问题:
当编译器无法使用它时,显式CodeNamespaceImport
语句的重点是什么?
我应该注意,完全省略添加我的命名空间根本不会改变输出:它保持原样。
答案 0 :(得分:3)
毫无疑问,typeof(List<int>)
在您的程序中是明确的,并且可以生成List的完整类型名称。你从哪里得到源列表还不是很清楚,我怀疑你使用了一个反汇编程序,它自动找出哪个使用指令最有用。
您可以像这样修改程序,看看编译器真正看到了什么:
var prov = CodeDomProvider.CreateProvider("C#");
var gen = prov.CreateGenerator();
using (var writer = new System.IO.StreamWriter("c:\\temp\\test.cs")) {
gen.GenerateCodeFromCompileUnit(ccUnit, writer, new CodeGeneratorOptions());
}
var result = prov.CompileAssemblyFromDom(parameters, ccUnit);
产生:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace SampleNamespace {
using System;
using System.Text;
using System.Threading;
public class SampleClass {
public System.Collections.Generic.List<int> _field = new System.Collections.Generic.List<int>();
}
}
正如您所知,编译器实际上看到了完整的类型名称,并且使用指令不是必需的。
答案 1 :(得分:1)
在IL级别,没有名称空间导入,所有类型总是使用其全名引用。
因此,当反编译器从IL生成C#时,它不知道原始代码包含的命名空间。这意味着合理的反编译器可能会生成导入类中使用的所有命名空间的代码(除非这会导致冲突)。