2011-02-11 109 views
5

我正在跟進我早期的問題:Mono.Cecil: call base class' method from other assembly
我正在做同樣的事情,但如果我的基類是通用的,它不起作用。Mono.Cecil:從其他程序集中調用GENERIC基類'方法

//in Assembly A 
class BaseVM<T> {} 

//in Assembly B 
class MyVM : Base<SomeModel> { 
[NotifyProperty] 
public string Something {get;set;} 
} 

它織下面的代碼:的

L_000e: call instance void [AssemblyA]Base`1::RaisePropertyChanged(string) 

代替

L_000e: call instance void [AssemblyA]Base`1<class SomeModel>::RaisePropertyChanged(string) 

有什麼改變?

+0

這個越來越相當重要的,請幫忙!!! – TDaver 2011-02-15 08:48:57

回答

16

在以前的信息表明您正在使用類似的代碼:

TypeDefinition type = ...; 
TypeDefintion baseType = type.BaseType.Resolve(); 
MethodDefinition baseMethod = baseType.Methods.First (m => ...); 
MethodReference baseMethodReference = type.Module.Import (baseMethod); 
il.Emit (OpCodes.Call, baseMethodReference); 

顯然,這是不適合於仿製藥:

當你Resolve()的.BaseType,你失去的泛型實例化信息。您需要使用基本類型中正確的通用信息重新創建適當的方法調用。

爲了簡化問題,讓我們用下面的方法,從塞西爾測試套件採取:

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; 
} 

有了這些,你可以重寫你的代碼爲:

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); 
+0

謝謝,它的工作! – TDaver 2011-02-15 10:17:05