0
我有这样一些代码的实例中使用的所有类型:写一个测试,以找到一个类
new ValidationFailure<AddSystemUserDto>
这是在我的应用服务层不同的地方,我想找到所有不同的“DTO “在代码中新增ValidationFailure时使用的类型,这是否可以使用反射?无需运行每个应用程序服务方法?
我有这样一些代码的实例中使用的所有类型:写一个测试,以找到一个类
new ValidationFailure<AddSystemUserDto>
这是在我的应用服务层不同的地方,我想找到所有不同的“DTO “在代码中新增ValidationFailure时使用的类型,这是否可以使用反射?无需运行每个应用程序服务方法?
是的。
我对这些类型的任务使用了一个小帮手类,我很方便地调用Decompiler
。基本上,将其转换为操作码的一个字节[] .NET代码:
public class ILInstruction
{
public ILInstruction(int offset, OpCode code, object operand)
{
this.Offset = offset;
this.Code = code;
this.Operand = operand;
}
// Fields
public int Offset { get; private set; }
public OpCode Code { get; private set; }
public object Operand { get; private set; }
}
internal class Decompiler
{
private Decompiler() { }
static Decompiler()
{
InitDecompiler();
}
private static OpCode[] singleByteOpcodes;
private static OpCode[] multiByteOpcodes;
private static void InitDecompiler()
{
singleByteOpcodes = new OpCode[0x100];
multiByteOpcodes = new OpCode[0x100];
FieldInfo[] infoArray1 = typeof(OpCodes).GetFields();
for (int num1 = 0; num1 < infoArray1.Length; num1++)
{
FieldInfo info1 = infoArray1[num1];
if (info1.FieldType == typeof(OpCode))
{
OpCode code1 = (OpCode)info1.GetValue(null);
ushort num2 = (ushort)code1.Value;
if (num2 < 0x100)
{
singleByteOpcodes[(int)num2] = code1;
}
else
{
if ((num2 & 0xff00) != 0xfe00)
{
throw new Exception("Invalid opcode: " + num2.ToString());
}
multiByteOpcodes[num2 & 0xff] = code1;
}
}
}
}
public static IEnumerable<ILInstruction> Decompile(MethodBase mi, byte[] ildata)
{
Module module = mi.Module;
ByteReader reader = new ByteReader(ildata);
while (!reader.Eof)
{
OpCode code = OpCodes.Nop;
int offset = reader.Position;
ushort b = reader.ReadByte();
if (b != 0xfe)
{
code = singleByteOpcodes[b];
}
else
{
b = reader.ReadByte();
code = multiByteOpcodes[b];
b |= (ushort)(0xfe00);
}
object operand = null;
switch (code.OperandType)
{
case OperandType.InlineBrTarget:
operand = reader.ReadInt32() + reader.Position;
break;
case OperandType.InlineField:
if (mi is ConstructorInfo)
{
operand = module.ResolveField(reader.ReadInt32(), mi.DeclaringType.GetGenericArguments(), Type.EmptyTypes);
}
else
{
operand = module.ResolveField(reader.ReadInt32(), mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments());
}
break;
case OperandType.InlineI:
operand = reader.ReadInt32();
break;
case OperandType.InlineI8:
operand = reader.ReadInt64();
break;
case OperandType.InlineMethod:
try
{
if (mi is ConstructorInfo)
{
operand = module.ResolveMember(reader.ReadInt32(), mi.DeclaringType.GetGenericArguments(), Type.EmptyTypes);
}
else
{
operand = module.ResolveMember(reader.ReadInt32(), mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments());
}
}
catch
{
operand = null;
}
break;
case OperandType.InlineNone:
break;
case OperandType.InlineR:
operand = reader.ReadDouble();
break;
case OperandType.InlineSig:
operand = module.ResolveSignature(reader.ReadInt32());
break;
case OperandType.InlineString:
operand = module.ResolveString(reader.ReadInt32());
break;
case OperandType.InlineSwitch:
int count = reader.ReadInt32();
int[] targetOffsets = new int[count];
for (int i = 0; i < count; ++i)
{
targetOffsets[i] = reader.ReadInt32();
}
int pos = reader.Position;
for (int i = 0; i < count; ++i)
{
targetOffsets[i] += pos;
}
operand = targetOffsets;
break;
case OperandType.InlineTok:
case OperandType.InlineType:
try
{
if (mi is ConstructorInfo)
{
operand = module.ResolveMember(reader.ReadInt32(), mi.DeclaringType.GetGenericArguments(), Type.EmptyTypes);
}
else
{
operand = module.ResolveMember(reader.ReadInt32(), mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments());
}
}
catch
{
operand = null;
}
break;
case OperandType.InlineVar:
operand = reader.ReadUInt16();
break;
case OperandType.ShortInlineBrTarget:
operand = reader.ReadSByte() + reader.Position;
break;
case OperandType.ShortInlineI:
operand = reader.ReadSByte();
break;
case OperandType.ShortInlineR:
operand = reader.ReadSingle();
break;
case OperandType.ShortInlineVar:
operand = reader.ReadByte();
break;
default:
throw new Exception("Unknown instruction operand; cannot continue. Operand type: " + code.OperandType);
}
yield return new ILInstruction(offset, code, operand);
}
}
}
从这一点来说,剩下的就是找到你调用构造函数时所使用的所有类型的问题(注:未经测试的代码,有可能出错:-):
IEnumerable<Type> FindDtoTypes()
{
foreach (var item in GetType().Assembly.GetTypes())
{
foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
{
var meth = member as MethodBase;
if (meth != null && meth.GetMethodBody() != null)
{
var code = meth.GetMethodBody().GetILAsByteArray();
foreach (var instr in Decompile(meth, code))
{
var oper = instr.Operand as MethodBase;
if (oper != null && oper.IsConstructor &&
oper.DeclaringType.IsGenericType)
{
var dtoType = mb.DeclaringType.GetGenericArguments().First();
if (dtoType.IsAssignableFrom(oper.DeclaringType))
yield return oper.DeclaringType;
}
}
}
}
}
}
_“这是可能使用反射” _ - 可能,但这需要你通过所有方法去挖掘,并找到所有'公共无效美孚(){返回新ValidationFailure ( ); }并且调用这个方法,这是一个令人厌恶的事情。您宁愿在编译时或之前使用静态分析,例如通过ReSharper或Roslyn执行此操作。你绝对不想自己编码。 –
CodeCaster