是否可以在 .NET 代码中找到泛型方法调用的所有具体类型?

Is it possible to find all concrete types of generic method calls in .NET code?

我正在编写一个 C# 代码生成器来序列化对象,以便通过网络发送它们。

起点是这个(简体):

public static partial class Serialization
{
    public static void Serialize<T>(in T value, DataStream stream)
    {
        throw new NotImplementedException($"Don't know how to serialize type {typeof(T)}!");
    }

    public static void Deserialize<T>(out T target, DataStream stream)
    {
        throw new NotImplementedException($"Don't know how to deserialize type {typeof(T)}!");
    }
}

现在,序列化代码生成器将为所有需要序列化的类型生成额外的非泛型 SerializeDeserialize 方法,例如结构 Vector3 和 public float 字段 xyz:

public static partial class Serialization
{
    // automatically generated method
    public static void Serialize(in Vector3 value, DataStream stream)
    {
        stream.Write(value.x);
        stream.Write(value.y);
        stream.Write(value.z);
    }

    // automatically generated method
    public static void Deserialize(out Vector3 target, DataStream stream)
    {
        target.x = stream.ReadFloat();
        target.y = stream.ReadFloat();
        target.z = stream.ReadFloat();
    }
}

开头显示的泛型方法仅用于在尚未(尚未)为某个类型生成序列化代码的情况下防止编译器错误。我需要编译代码,否则我无法对其使用反射。

目前我必须使用自定义 EnableSerialization 属性标记需要序列化代码的类型。

理想情况下,生成器会查看编译后的代码(使用静态代码分析),识别可能传递给通用 SerializeDeserialize 方法的类型,然后生成代码那些类型。因此,例如,如果我的代码中某处有这个:

int x = 42;
Serialization.Serialize(x, new DataStream());

然后代码生成器应该选择 int 作为需要序列化代码的类型。

是否有这种努力的任何秘诀,或者 .NET 库或第三方库中是否有任何东西可以促进这一点?

(我考虑过 运行 时间代码生成,但我更愿意将其作为预处理步骤。)

使用 Mono.Reflection,您可以执行以下操作:

HashSet<Type> types = new HashSet<Type>();
Assembly assembly = Assembly.LoadFile(@"<Path>");

foreach (Module module in assembly.GetModules())
{
  foreach (Type type in module.GetTypes())
  {
    // GetMethodBody() should not be null since otherwise Disassembler.GetInstructions would throw an exception
    foreach (MethodInfo method in type.GetMethods().Where(m => m.GetMethodBody() != null))
    {
      foreach (Instruction instruction in Disassembler.GetInstructions(method))
      {
        // instruction.Operand being MethodInfo most probably means a call instrution.
        // Not sure if this always true
        MethodInfo called = instruction.Operand as MethodInfo;

        if (called != null && called.DeclaringType.Name.Equals("Serialization") && called.Name.Equals("Serialize"))
        {
          types.Add(called.GetParameters()[0].ParameterType);
        }
      }
    }
  }
}

DisassemblerInstruction 都是 Mono.Reflection 的一部分。
现在,您已将所有使用的类型传递给 types.

中的 Serialization.Serialize