0

我正在使用Unity進行截取。因爲我有很多接口,我不得不使用VirtualMethodInterceptor。在我的行爲中,我只想在所調用的方法在特定類型的接口(具有特殊屬性)中聲明時作出反應。我認爲MethodBase.DeclaringType可以解決我的問題,但它的行爲與我所期望的不同。它返回實現類型。如何查找聲明方法的接口

我可以同意,它是有道理的,因爲該方法可以在多個接口中聲明,但應該有一種方法來輕鬆獲取它們的列表。不幸的是,我還沒有找到它。

小樣本顯示我的問題

public interface ISample 
{ 
    void Do(); 
} 

public class Sample : ISample 
{ 
    public void Do() 
    { 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var m = typeof(Sample).GetMethod("Do") as MethodBase; 
     Console.WriteLine(m.DeclaringType.Name); // Prints "Sample" 
    } 
} 

一個尷尬的解決方案

var interfaces = from i in input.MethodBase.DeclaringType.GetInterfaces() 
       where i.GetCustomAttributes(typeof(CustomAttribute), true).Length > 0 
       where i.GetMethod(input.MethodBase.Name, input.MethodBase.GetParameters().Select(p=>p.ParameterType).ToArray()) != null 
       select i; 
+0

發佈您的尷尬解決方案作爲答案並接受它。尷尬的要求有尷尬的解決方案。 –

+0

但我真的需要枚舉所有接口和所有參數。我不知道這是否是一個尷尬的要求,但我期望從運行時獲得更好的幫助。 – StanislawSwierc

回答

0

唯一的解決辦法我能想出(類似於你不那麼尷尬的解決方案雖然)。

public static bool IsMethodDeclaredInInterface(MethodBase method, Type myInterface) 
{ 
    var methodType = method.DeclaringType; 
    var typeFilter = new TypeFilter((t, crit) => 
             { 
              var critTypes = crit as Type[]; 
              return critTypes != null && critTypes.Any(ty => ty.FullName == t.FullName); 
             }); 
    var res = methodType.FindInterfaces(typeFilter, new[] {myInterface}); 
    return res.Length > 0; 
} 
+0

在我看來,你的解決方案只會檢查實現類型是否實現給定的接口。雖然TypeFilter是完全不同的方法,但是它從初始版本的框架返回並且其實現枚舉所有接口,應用過濾標準並將它們存儲回數組,因此在性能方面這應該類似於我的尷尬解決方案。 – StanislawSwierc

0

最後我用這個代碼:

var interfaces = from i in input.MethodBase.DeclaringType.GetInterfaces() 
       let parameters = input.MethodBase.GetParameters().Select(p=>p.ParameterType).ToArray() 
       where i.GetCustomAttributes(typeof(CustomAttribute), true).Length > 0 
       where i.GetMethod(input.MethodBase.Name, parameters) != null 
       select i; 
0

我覺得你被卡住枚舉接口;我還沒有看到訪問特定界面的方法。

此外,如果接口是明確實現的,則會出現小邊緣情況。在這種情況下(void ISample.Do()),MethodBase.Name將是完全限定的方法名稱(例如MyApp.ISample.Do),而不是Do

我發現的唯一解決方案是去掉主要信息。例如。

string methodName = input.MethodBase.Name; 
int methodIndex = methodName.LastIndexOf('.'); 

if (methodIndex != -1) 
{ 
    methodName = methodName.Substring(methodIndex + 1, 
     methodName.Length - methodIndex - 1); 
} 

var interfaces = from i in input.MethodBase.DeclaringType.GetInterfaces() 
       let parameters = input.MethodBase.GetParameters(). 
        Select(p => p.ParameterType).ToArray() 
       where i.GetCustomAttributes(typeof(CustomAttribute), true).Length > 0 
       where i.GetMethod(methodName, parameters) != null 
       select i; 

而且,如果存在具有相同的名稱和簽名,然後我不知道如何來確定方法,通過該接口被稱爲相對於公有方法的另一種方法。

public class Sample : ISample 
{ 
    public void Do() 
    { 
     // this is a public method 
    } 

    void ISample.Do() 
    { 
     // this is the interface implementation 
    } 
} 

我想有可能找到其他方法具有相同的名稱和簽名,並通過查看其他MethodBase屬性來區分。

I.e. public void Do()將IsHideBySig和IsPublic設置爲true,而void ISample.Do()將IsFinal,IsVirtual,IsPrivate,IsHideBySig全部設置爲true。但我不確定這對所有情況都是足夠的。