为类型创建指令
Create an Instruction for Type
使用Mono.Cecil,给出这个方法
private Instruction LoadOnStack(MetadataType type, object value)
{
switch (type)
{
case MetadataType.String:
return _processor.Create(OpCodes.Ldstr, (string) value);
case MetadataType.Int32:
return _processor.Create(OpCodes.Ldc_I4, (Int32) value);
case MetadataType.Int64:
return _processor.Create(OpCodes.Ldc_I8, (Int64) value);
case MetadataType.Boolean:
return _processor.Create(OpCodes.Ldc_I4, (bool) value ? 1 : 0);
}
throw new NotSupportedException("Not a supported primitve parameter type: " + type);
}
当 value
的类型为 Type
时,如何创建可以加载 value
的 Instruction
?
我注意到当 value
是 Type
类型时,我可以像这样测试它:
if (value is TypeReference)
return _processor.Create(???, ???);
但我无法弄清楚我需要传递给 Create
什么才能正确加载值。
编辑:
使用这个:
if (value is TypeReference)
return _processor.Create(OpCodes.Ldobj, type.Resolve());
让我更近一步。它似乎接受类型。但是当我尝试编写程序集时,它会出错:
System.ArgumentException : Member 'System.Type' is declared in another module and needs to be imported
正如@cubrr 已经指出的:
我们将此代码用于 MethodBoundaryAspect.Fody
private IList<Instruction> LoadValueOnStack(TypeReference parameterType, object value, ModuleDefinition module)
{
if (parameterType.IsPrimitive || (parameterType.FullName == "System.String"))
return new List<Instruction> {LoadPrimitiveConstOnStack(parameterType.MetadataType, value)};
if (parameterType.IsValueType) // enum
{
var enumUnderlyingType = GetEnumUnderlyingType(parameterType.Resolve());
return new List<Instruction> {LoadPrimitiveConstOnStack(enumUnderlyingType.MetadataType, value)};
}
if (parameterType.FullName == "System.Type")
{
var typeName = value.ToString();
var typeReference = module.GetType(typeName, true);
var typeTypeRef = _referenceFinder.GetTypeReference(typeof (Type));
var methodReference = _referenceFinder.GetMethodReference(typeTypeRef, md => md.Name == "GetTypeFromHandle");
var instructions = new List<Instruction>
{
_processor.Create(OpCodes.Ldtoken, typeReference),
_processor.Create(OpCodes.Call, methodReference)
};
return instructions;
}
throw new NotSupportedException("Parametertype: " + parameterType);
}
private Instruction LoadPrimitiveConstOnStack(MetadataType type, object value)
{
switch (type)
{
case MetadataType.String:
return _processor.Create(OpCodes.Ldstr, (string) value);
case MetadataType.Int32:
return _processor.Create(OpCodes.Ldc_I4, (int) value);
case MetadataType.Int64:
return _processor.Create(OpCodes.Ldc_I8, (long) value);
case MetadataType.Boolean:
return _processor.Create(OpCodes.Ldc_I4, (bool) value ? 1 : 0);
}
throw new NotSupportedException("Not a supported primitive parameter type: " + type);
}
private static TypeReference GetEnumUnderlyingType(TypeDefinition self)
{
foreach (var field in self.Fields)
{
if (field.Name == "value__")
return field.FieldType;
}
throw new ArgumentException();
}
其中 class ReferenceFinder 是:
private readonly ModuleDefinition _moduleDefinition;
public ReferenceFinder(ModuleDefinition moduleDefinition)
{
_moduleDefinition = moduleDefinition;
}
public MethodReference GetMethodReference(Type declaringType, Func<MethodDefinition, bool> predicate)
{
return GetMethodReference(GetTypeReference(declaringType), predicate);
}
public MethodReference GetMethodReference(TypeReference typeReference, Func<MethodDefinition, bool> predicate)
{
var typeDefinition = typeReference.Resolve();
MethodDefinition methodDefinition;
do
{
methodDefinition = typeDefinition.Methods.FirstOrDefault(predicate);
typeDefinition = typeDefinition.BaseType == null
? null
: typeDefinition.BaseType.Resolve();
} while (methodDefinition == null && typeDefinition != null);
return _moduleDefinition.Import(methodDefinition);
}
public TypeReference GetTypeReference(Type type)
{
return _moduleDefinition.Import(type);
}
使用Mono.Cecil,给出这个方法
private Instruction LoadOnStack(MetadataType type, object value)
{
switch (type)
{
case MetadataType.String:
return _processor.Create(OpCodes.Ldstr, (string) value);
case MetadataType.Int32:
return _processor.Create(OpCodes.Ldc_I4, (Int32) value);
case MetadataType.Int64:
return _processor.Create(OpCodes.Ldc_I8, (Int64) value);
case MetadataType.Boolean:
return _processor.Create(OpCodes.Ldc_I4, (bool) value ? 1 : 0);
}
throw new NotSupportedException("Not a supported primitve parameter type: " + type);
}
当 value
的类型为 Type
时,如何创建可以加载 value
的 Instruction
?
我注意到当 value
是 Type
类型时,我可以像这样测试它:
if (value is TypeReference)
return _processor.Create(???, ???);
但我无法弄清楚我需要传递给 Create
什么才能正确加载值。
编辑:
使用这个:
if (value is TypeReference)
return _processor.Create(OpCodes.Ldobj, type.Resolve());
让我更近一步。它似乎接受类型。但是当我尝试编写程序集时,它会出错:
System.ArgumentException : Member 'System.Type' is declared in another module and needs to be imported
正如@cubrr 已经指出的:
我们将此代码用于 MethodBoundaryAspect.Fody
private IList<Instruction> LoadValueOnStack(TypeReference parameterType, object value, ModuleDefinition module)
{
if (parameterType.IsPrimitive || (parameterType.FullName == "System.String"))
return new List<Instruction> {LoadPrimitiveConstOnStack(parameterType.MetadataType, value)};
if (parameterType.IsValueType) // enum
{
var enumUnderlyingType = GetEnumUnderlyingType(parameterType.Resolve());
return new List<Instruction> {LoadPrimitiveConstOnStack(enumUnderlyingType.MetadataType, value)};
}
if (parameterType.FullName == "System.Type")
{
var typeName = value.ToString();
var typeReference = module.GetType(typeName, true);
var typeTypeRef = _referenceFinder.GetTypeReference(typeof (Type));
var methodReference = _referenceFinder.GetMethodReference(typeTypeRef, md => md.Name == "GetTypeFromHandle");
var instructions = new List<Instruction>
{
_processor.Create(OpCodes.Ldtoken, typeReference),
_processor.Create(OpCodes.Call, methodReference)
};
return instructions;
}
throw new NotSupportedException("Parametertype: " + parameterType);
}
private Instruction LoadPrimitiveConstOnStack(MetadataType type, object value)
{
switch (type)
{
case MetadataType.String:
return _processor.Create(OpCodes.Ldstr, (string) value);
case MetadataType.Int32:
return _processor.Create(OpCodes.Ldc_I4, (int) value);
case MetadataType.Int64:
return _processor.Create(OpCodes.Ldc_I8, (long) value);
case MetadataType.Boolean:
return _processor.Create(OpCodes.Ldc_I4, (bool) value ? 1 : 0);
}
throw new NotSupportedException("Not a supported primitive parameter type: " + type);
}
private static TypeReference GetEnumUnderlyingType(TypeDefinition self)
{
foreach (var field in self.Fields)
{
if (field.Name == "value__")
return field.FieldType;
}
throw new ArgumentException();
}
其中 class ReferenceFinder 是:
private readonly ModuleDefinition _moduleDefinition;
public ReferenceFinder(ModuleDefinition moduleDefinition)
{
_moduleDefinition = moduleDefinition;
}
public MethodReference GetMethodReference(Type declaringType, Func<MethodDefinition, bool> predicate)
{
return GetMethodReference(GetTypeReference(declaringType), predicate);
}
public MethodReference GetMethodReference(TypeReference typeReference, Func<MethodDefinition, bool> predicate)
{
var typeDefinition = typeReference.Resolve();
MethodDefinition methodDefinition;
do
{
methodDefinition = typeDefinition.Methods.FirstOrDefault(predicate);
typeDefinition = typeDefinition.BaseType == null
? null
: typeDefinition.BaseType.Resolve();
} while (methodDefinition == null && typeDefinition != null);
return _moduleDefinition.Import(methodDefinition);
}
public TypeReference GetTypeReference(Type type)
{
return _moduleDefinition.Import(type);
}