Mono.Cecil:chamada de classe base GENÉRICA' método de assembly
-
12-11-2019 - |
Pergunta
Eu vou seguir a minha pergunta anterior: Mono.Cecil:chamada de classe base' método de assembly.
Eu estou fazendo a mesma coisa, mas se minha classe base é genérico não funciona.
//in Assembly A
class BaseVM<T> {}
//in Assembly B
class MyVM : Base<SomeModel> {
[NotifyProperty]
public string Something {get;set;}
}
Ele tece o seguinte código:
L_000e: call instance void [AssemblyA]Base`1::RaisePropertyChanged(string)
em vez de
L_000e: call instance void [AssemblyA]Base`1<class SomeModel>::RaisePropertyChanged(string)
O que há para mudar?
Solução
No post anterior você indicar que você está usando um código como:
TypeDefinition type = ...;
TypeDefintion baseType = type.BaseType.Resolve ();
MethodDefinition baseMethod = baseType.Methods.First (m => ...);
MethodReference baseMethodReference = type.Module.Import (baseMethod);
il.Emit (OpCodes.Call, baseMethodReference);
Obviamente, este não é adequado para os genéricos:
Quando você Resolve ()
a .BaseType, você está perdendo o genérico de instanciação de informações.Você precisa recriar o método apropriado chamar com as devidas informações genéricas do tipo base.
Para simplificar as coisas, vamos usar os métodos a seguir, retirado do Cecil conjunto de teste:
public static TypeReference MakeGenericType (this TypeReference self, params TypeReference [] arguments)
{
if (self.GenericParameters.Count != arguments.Length)
throw new ArgumentException ();
var instance = new GenericInstanceType (self);
foreach (var argument in arguments)
instance.GenericArguments.Add (argument);
return instance;
}
public static MethodReference MakeGeneric (this MethodReference self, params TypeReference [] arguments)
{
var reference = new MethodReference(self.Name,self.ReturnType) {
DeclaringType = self.DeclaringType.MakeGenericType (arguments),
HasThis = self.HasThis,
ExplicitThis = self.ExplicitThis,
CallingConvention = self.CallingConvention,
};
foreach (var parameter in self.Parameters)
reference.Parameters.Add (new ParameterDefinition (parameter.ParameterType));
foreach (var generic_parameter in self.GenericParameters)
reference.GenericParameters.Add (new GenericParameter (generic_parameter.Name, reference));
return reference;
}
Com elas, você pode reescrever seu código como:
TypeDefinition type = ...;
TypeDefintion baseTypeDefinition = type.BaseType.Resolve ();
MethodDefinition baseMethodDefinition = baseTypeDefinition.Methods.First (m => ...);
MethodReference baseMethodReference = type.Module.Import (baseMethodDefinition);
if (type.BaseType.IsGenericInstance) {
var baseTypeInstance = (GenericInstanceType) type.BaseType;
baseMethodReference = baseMethodReference.MakeGeneric (baseTypeInstance.GenericArguments.ToArray ());
}
il.Emit (OpCodes.Call, baseMethodReference);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow