2010-10-01 34 views
5

是否可以從調用堆棧反映顯式接口實現?我想用這個信息來查看接口本身的一個屬性。如何從調用堆棧反思C#顯式接口的實現?

鑑於此代碼:

interface IFoo 
{ 
    void Test();  
} 

class Foo : IFoo 
{ 
    void IFoo.Test() { Program.Trace(); } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     IFoo f = new Foo(); 
     f.Test(); 
    } 

    public static void Trace() 
    { 
     var method = new StackTrace(1, false).GetFrame(0).GetMethod(); 
     // method.??? 
    } 
} 

具體而言,在跟蹤(),我希望能夠從method得到typeof(IFoo)

在觀察窗口中,如果我看method.ToString()它給我Void InterfaceReflection.IFoo.Test()(InterfaceReflection是我的程序集的名稱)。

如何從那裏到typeof(IFoo)?我必須從程序集本身使用基於名稱的類型查找,還是有Type IFoo隱藏在MethodBase的某處?

UPDATE:

下面是最終的解決方案,這要歸功於凱特

public static void Trace() 
{ 
    var method = new StackTrace(1, false).GetFrame(0).GetMethod(); 
    var parts = method.Name.Split('.'); 
    var iname = parts[parts.Length - 2]; 
    var itype = method.DeclaringType.GetInterface(iname); 
} 

itype將會對實現方法的接口類型。這隻會與顯式接口實現一起工作,但這正是我需要的。現在我可以使用itype來查詢附加到實際接口類型的屬性。

感謝大家的幫助。

回答

3

使用VS2010進行測試,我發現了DeclaringType,它從包含該方法的對象類型中獲取接口作爲Type對象。

public static void Trace() { 
     var stack = new StackTrace(1, true); 
     var frame = stack.GetFrame(0); 
     var method = frame.GetMethod(); 

     var type = method.DeclaringType; 

     Console.WriteLine(type); 
     foreach (var i in type.GetInterfaces()) { 
      Console.WriteLine(i); 
     } 
    } 

返回:

TestConsole.Foo 
TestConsole.IFoo 

(我稱之爲項目TestConsole)

+0

啊!就是這樣,謝謝。我只是在看房地產,並沒有考慮看方法。我認爲'GetInterfaces()'是我可以使用的。我將使用'method.Name',它給了我'InterfaceReflection.IFoo.Test',我將取出「IFoo」,並使用'GetInterface()'來找到它的匹配類型。這樣可行。 – scobi 2010-10-01 18:08:05

+0

如果Foo實現了多於一個接口,那麼您仍然必須弄清楚該方法屬於哪一個接口。另外,如果接口中未定義Test,並且是Foo的實際方法,該怎麼辦? – CodingWithSpike 2010-10-01 18:31:41

+0

@ rally25rs:您可以運行i.GetMethods()並與GetFrame(0).GetMethod() – Kyte 2010-10-01 18:48:54

0

我不想假設太多,但在這種情況下,看起來您可能會造成一些混淆,因爲Foo和程序是相互依賴的。通常情況下,我會認爲程序會「擁有」Foo(這與程序不可知),因此它負責設置代表,這樣可以避免反射......您設置的方式,Foo「擁有「(實際上,我猜的依賴可能更準確)程序(因爲它調用了Program.Trace()),程序」擁有「了Foo(因爲它控制着實例)。

我不知道這是否適用於您的特定場景,但它看起來像一個事件類型操作可能更有意義,並更簡單地處理通信。

ETA:代碼示例:

public interface IFoo 
{ 
    event EventHandler Testing; 
    void Test(); 
} 
public class Foo : IFoo 
{ 
    public event EventHandler Testing; 
    protected void OnTesting(EventArgs e) 
    { 
     if (Testing != null) 
      Testing(this, e); 
    } 
    public void Test() 
    { 
     OnTesting(EventArgs.Empty); 
    } 
} 

static class Program 
{ 
    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main() 
    { 
     IFoo f = new Foo(); 
     f.Testing += new EventHandler(f_Testing); 
     f.Test(); 
    } 

    static void f_Testing(object sender, EventArgs e) 
    { 
     IFoo foo = sender as IFoo; 
     if (foo != null) 
     { 
      //... 
     } 
    } 
} 

我可能會誤解你的問題,但。

+0

你肯定是誤會我的問題。 :)這僅僅是爲了以最簡單的方式提出問題而設計的。我真的只是對(a)如何正確反思以及(b)這個InterfaceReflection.exe業務是什麼感興趣。這個問題不是關於建築設計。 – scobi 2010-10-01 17:17:45

2

method將是System.Reflection.RuntimeMethodInfo,它是從System.Reflect.MethodBase派生的類。你可以例如調用Invoke()就可以了(雖然如果你在獲得它的地方這樣做了,那麼這將導致無限遞歸,最終因堆棧溢出而死亡)。

上調用ToString()返回一個完全限定的名稱。你有沒有調用項目InterfaceReflection?

不知道你想要什麼比。

編輯:好的,現在我知道了。要查找聲明類型,請查看DeclaringType屬性,這將返回聲明方法的類(可能是它所調用的類或基類):

到目前爲止這麼簡單,返回Foo的一個Type對象。

現在的棘手一點,因爲你關心它聲明的接口。但是,可能有多個接口定義了一個具有完全相同簽名的方法,這意味着一個簡單的問題:「如果它來自一個接口,那個接口是什麼?」並不總是有一個單一的答案。

有可能是一個更好的方法來做到這一點,但我所能想到的只是從​​得到的Type對象上調用GetInterfaces(),然後查找名稱與方法簽名相匹配的對象。

+0

哇。口中。我確實調用了InterfaceReflection項目並忘記了它。我在想這是一個內部.NET名稱。好的,我會更新問題。我仍然有找到正確的接口類型的問題。 – scobi 2010-10-01 17:34:41

+0

@斯科特比拉斯好,相應地更新了我的答案。 – 2010-10-01 18:19:15

0

我認爲.NET追加全名的MethodInfo.Name屬性的前面,使得它具有獨特的每種方法的名稱。想想:

interface IFoo 
{ 
    void Test(); 
} 
interface IFoo2 
{ 
    void Test(); 
} 

class Foo : IFoo, IFoo2 
{ 
    void IFoo.Test() { Trace(); } 
    void IFoo2.Test() { Trace(); } 
} 

在這種情況下,typeof(Foo).GetMethods()將返回兩個Test()方法,但他們的名字會衝突,所以我想他們附加的接口名稱,使它們獨特之處?

MethodInfo.DeclaringType返回包含實現的類型。因此,如果IFoo實際上是一些基本類型而不是接口,並且在那裏有一個基本方法聲明,那麼.DeclaringType將返回基類的類型。

有趣的是,我似乎無法在任何地方的MethodInfo發現實際的接口名稱或者,所以我想你將不得不通過名字來關注一下吧,是這樣的:

public static void Trace() 
    { 
     var method = new System.Diagnostics.StackTrace(1, false).GetFrame(0).GetMethod(); 
     var fromType = method.DeclaringType; 
     if (method.Name.Contains(".")) 
     { 
      var iname = method.Name.Substring(0, method.Name.LastIndexOf('.')); 
      fromType = Type.GetType(iname); // fromType is now IFoo. 
     } 
    }