C# 反射和自动生成类型

C# 反射和自动生成类型,c#,vb.net,system.reflection,yield-return,C#,Vb.net,System.reflection,Yield Return,我有一个类,它有一个使用“yield”返回语句的方法。将自动创建嵌套类型。使用绑定标志设置为BindingFlags.DeclaredOnly的反射,我得到以下输出: //我班的公众成员。 Test.FileSystemObject..ctor Test.FileSystemObject.GetFiles(DirectoryInfo目录) Test.FileSystemObject.GetFiles(字符串路径) //自动生成的嵌套类。 Test.FileSystemObject+d\u 4..

我有一个类,它有一个使用“yield”返回语句的方法。将自动创建嵌套类型。使用绑定标志设置为
BindingFlags.DeclaredOnly
的反射,我得到以下输出:

//我班的公众成员。
Test.FileSystemObject..ctor
Test.FileSystemObject.GetFiles(DirectoryInfo目录)
Test.FileSystemObject.GetFiles(字符串路径)

//自动生成的嵌套类。
Test.FileSystemObject+d\u 4..ctor
Test.FileSystemObject+d\u4.3\uu目录
Test.FileSystemObject+d_u4.4_u
Test.FileSystemObject+d\u 4.5\u 7
Test.FileSystemObject+d_u4.5_u8
Test.FileSystemObject+d_u4.5_u6
Test.FileSystemObject+d\u 4.5\u 9
Test.FileSystemObject+d__4.5__5
Test.FileSystemObject+d__4.0目录

如何确定
assembly.GetTypes(BindingsFlags)
返回的类型是否是自动生成的类型?我正在寻找一种简单的方法来排除这些问题。

您可以测试该类型是否具有
[CompilerGenerated]
属性:

if (type.GetCustomAttribute(typeof(CompilerGeneratedAttribute), true) != null)
{
    ...
}

或者,您可以检查名称是否包含在用户代码中无效的字符。

您可以在运行时编写代码,使用CSharpCodeProvider()进行编译。compileasemblyFromSource()并在当前程序集域中注册您的类型。 只要域存在,它就会驻留在那里。从结果中调用“get”访问器会自动将“Load”方法从已编译的程序集调用到当前应用程序域中

您还可以使用创建您的类型。此外,您可以强制属性标志显示为编译器生成的或此处的其他属性

var infoConstructor = typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes);

typeBuilder.SetCustomAttribute(infoConstructor, new byte[] { });
下面是我今天工作的一个例子。它的目的不仅仅是为了可视化,而是作为所有逆向工程类代码的自动生成实体集合。似乎比使用带T4和XML输出转储的文件I/O要好。尽管如此,让X-Doc/oxygen自动生成HTMLWiki页面,并在下一个PDB构建中使用和编译代码,仍然是一个可行的选择。不是一个臃肿的粉丝,请继续思考

    /// <summary>
    ///   CreateType
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="name"></param>
    /// <param name="properties"></param>
    /// <param name="accessor"></param>
    /// <param name="hasSubTypes"></param>
    /// <returns>The newly created type of the object.</returns>
    internal static Type CreateType(this Mirror obj, string name, IEnumerable<string> properties, string accessor = "", bool hasSubTypes = false) {
      Type subTypeRef = null;

      // Tested Regex @ http://regex101.com
      const string subTypes = @"(?:<|(?:\$))([a-zA-Z_]+[0-9`]*)(?:>([a-zA-Z_]+[0-9`]*))";
      var match = Regex.Match(name, subTypes);

      if (match.Success) {
        var refType = match.Groups[1].Value; // Class reference type.
        if (match.Groups[2].Success && !string.IsNullOrEmpty(match.Groups[2].Value))
          accessor = match.Groups[2].Value; // Class accessor.

        // ReSharper disable once TailRecursiveCall
        var enumerable = properties as IList<string> ?? properties.ToList();
        subTypeRef = CreateType(obj, refType, enumerable, accessor, true);

        // Tokenize this for the actual derived class name.
        name = name.Substring(0, name.IndexOf('+'));
      }

      // Check if formating of the class name matches traditional valid syntax.
      // Assume at least 3 levels deep.
      var toks = name.Split(new[] { '+' }, StringSplitOptions.RemoveEmptyEntries);
      Type type = null;

      foreach (var tok in toks.Reverse()) {
        var o = obj.RefTypes.FirstOrDefault(t => t.Value.Name == tok);
        if (!o.Equals(default(KeyValuePair<string, Type>)))
          continue;

        // Not exists.
        var sb = new StringBuilder();
        sb.Append(@"
using System;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
using System.Linq;

namespace HearthMirror.TypeBuilder {
  [CompilerGenerated]
  public class ").Append(tok).AppendLine(@" {");

        if (subTypeRef != null)
          sb.AppendLine($"  public {subTypeRef.Name} {accessor}").AppendLine(" { get; set; }");

        sb.Append("  }\n}");

        var asm = RuntimeCodeCompiler.CompileCode(sb.ToString());
        type = asm.GetType($"{MethodBase.GetCurrentMethod().ReflectedType?.Namespace}.{tok}"); // => generated

        // Register our type for reference.   This container will handle collisions and throw if encountered.
        obj.RefTypes.Add(tok, type);
      }

      return type;
    }
//
///创建类型
/// 
/// 
/// 
/// 
/// 
/// 
///新创建的对象类型。
内部静态类型CreateType(此镜像对象,字符串名称,IEnumerable属性,字符串访问器=”,bool hasSubTypes=false){
类型subtyref=null;
//测试正则表达式@http://regex101.com
常量字符串子类型=@“(?:([a-zA-Z!]+[0-9`]*)”;
var match=Regex.match(名称、子类型);
如果(匹配成功){
var refType=match.Groups[1].Value;//类引用类型。
if(match.Groups[2].Success&&!string.IsNullOrEmpty(match.Groups[2].Value))
accessor=match.Groups[2].Value;//类访问器。
//ReSharper禁用一次TailRecursiveCall
var enumerable=作为IList的属性??properties.ToList();
SubsubRef=CreateType(obj,refType,可枚举,访问器,true);
//将其标记为实际的派生类名。
name=name.Substring(0,name.IndexOf(+');
}
//检查类名的格式是否与传统的有效语法匹配。
//假设至少有3层深。
var toks=name.Split(新[]{'+'},StringSplitOptions.RemoveEmptyEntries);
Type=null;
foreach(toks.Reverse()中的var tok){
var o=obj.RefTypes.FirstOrDefault(t=>t.Value.Name==tok);
如果(!o.Equals(默认值(KeyValuePair)))
继续;
//不存在。
var sb=新的StringBuilder();
某人附加(@)
使用制度;
使用System.Runtime.CompilerServices;
使用System.Collections.Generic;
使用System.Linq;
命名空间HearthMirror.TypeBuilder{
[编译生成]
公共类“).Append(tok.AppendLine(@“{”);
if(subsubscref!=null)
sb.AppendLine($“public{submitref.Name}{accessor}”).AppendLine({get;set;}”);
sb.追加(“}\n}”);
var asm=RuntimeCodeCompiler.CompileCode(sb.ToString());
type=asm.GetType($“{MethodBase.GetCurrentMethod().ReflectedType?.Namespace}.{tok}”);//=>已生成
//注册我们的类型以供引用。如果遇到冲突,此容器将处理冲突和抛出。
对象参照类型添加(tok,类型);
}
返回类型;
}

//
///编译代码
/// 
/// 
/// 
公共静态程序集编译码(字符串代码){
var provider=新的CSharpCodeProvider();
var compilerparams=new CompilerParameters{GenerateExecutable=false,GenerateInMemory=true,IncludeDebugInformation=true};
foreach(AppDomain.CurrentDomain.GetAssemblys()中的变量程序集){
试一试{
var位置=程序集位置;
如果(!string.IsNullOrEmpty(位置))
compilerparams.ReferencedAssembly.Add(位置);
}捕获(不支持异常){
//这种情况发生在动态程序集上,所以忽略它。
}
}
var results=provider.compileAsemblyFromSource(编译器参数,代码);
if(results.Errors.HasErrors){
var errors=new StringBuilder(“编译器错误:\r\n”);
foreach(结果中的编译器错误。错误)
errors.AppendFormat(“行{0},{1}\t:{2}\n”、error.Line、error.Column、error.ErrorText);
抛出新异常(errors.ToString());
}
AppDomain.CurrentDomain.Load(results.CompiledAssembly.GetName());
返回results.CompiledAssembly;
}

具体来说,我认为C编译器生成的所有类型都包含
。虽然这显然是一个实现细节。@svick:细节在这里,是的,它们可能会发生变化:@Thomas Levesque:我测试了你的代码,它工作了。但是,使用ReflectionOnlyLoadFrom(路径)加载程序集时引发了异常。快速搜索后,使用CustomAttri
    /// <summary>
    ///   CreateType
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="name"></param>
    /// <param name="properties"></param>
    /// <param name="accessor"></param>
    /// <param name="hasSubTypes"></param>
    /// <returns>The newly created type of the object.</returns>
    internal static Type CreateType(this Mirror obj, string name, IEnumerable<string> properties, string accessor = "", bool hasSubTypes = false) {
      Type subTypeRef = null;

      // Tested Regex @ http://regex101.com
      const string subTypes = @"(?:<|(?:\$))([a-zA-Z_]+[0-9`]*)(?:>([a-zA-Z_]+[0-9`]*))";
      var match = Regex.Match(name, subTypes);

      if (match.Success) {
        var refType = match.Groups[1].Value; // Class reference type.
        if (match.Groups[2].Success && !string.IsNullOrEmpty(match.Groups[2].Value))
          accessor = match.Groups[2].Value; // Class accessor.

        // ReSharper disable once TailRecursiveCall
        var enumerable = properties as IList<string> ?? properties.ToList();
        subTypeRef = CreateType(obj, refType, enumerable, accessor, true);

        // Tokenize this for the actual derived class name.
        name = name.Substring(0, name.IndexOf('+'));
      }

      // Check if formating of the class name matches traditional valid syntax.
      // Assume at least 3 levels deep.
      var toks = name.Split(new[] { '+' }, StringSplitOptions.RemoveEmptyEntries);
      Type type = null;

      foreach (var tok in toks.Reverse()) {
        var o = obj.RefTypes.FirstOrDefault(t => t.Value.Name == tok);
        if (!o.Equals(default(KeyValuePair<string, Type>)))
          continue;

        // Not exists.
        var sb = new StringBuilder();
        sb.Append(@"
using System;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
using System.Linq;

namespace HearthMirror.TypeBuilder {
  [CompilerGenerated]
  public class ").Append(tok).AppendLine(@" {");

        if (subTypeRef != null)
          sb.AppendLine($"  public {subTypeRef.Name} {accessor}").AppendLine(" { get; set; }");

        sb.Append("  }\n}");

        var asm = RuntimeCodeCompiler.CompileCode(sb.ToString());
        type = asm.GetType($"{MethodBase.GetCurrentMethod().ReflectedType?.Namespace}.{tok}"); // => generated

        // Register our type for reference.   This container will handle collisions and throw if encountered.
        obj.RefTypes.Add(tok, type);
      }

      return type;
    }
/// <summary>
///  CompileCode
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
public static Assembly CompileCode(string code) {
  var provider = new CSharpCodeProvider();
  var compilerparams = new CompilerParameters { GenerateExecutable = false, GenerateInMemory = true, IncludeDebugInformation = true };

  foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) {
    try {
      var location = assembly.Location;
      if (!string.IsNullOrEmpty(location))
        compilerparams.ReferencedAssemblies.Add(location);
    } catch (NotSupportedException) {
      // this happens for dynamic assemblies, so just ignore it. 
    }
  }

  var results = provider.CompileAssemblyFromSource(compilerparams, code);
  if (results.Errors.HasErrors) {
    var errors = new StringBuilder("Compiler Errors :\r\n");
    foreach (CompilerError error in results.Errors)
      errors.AppendFormat("Line {0},{1}\t: {2}\n", error.Line, error.Column, error.ErrorText);
    throw new Exception(errors.ToString());
  }
  AppDomain.CurrentDomain.Load(results.CompiledAssembly.GetName());
  return results.CompiledAssembly;
}