2011-01-06 46 views
0

我有一個接口ITest,方法爲GetResult()。我有一個類Test實現ITest,從而定義私有方法GetResult()。在VB.NET中使用System.Object類型變量調用接口方法

接下來,我在另一個類中創建一個Test實例。代碼如下:

Module NewClass 
    Public Sub New() 
     Dim i As ITest = New Test() 

     Dim o As Object 
     o = i 

     Dim b As Boolean = o.GetResult() 'This line raises "MissingMemberException" Public member 'Certify' on type 'Class1' not found. ' 
    End Sub 
End Module 

我必須Object o引用這個,因爲我有其他代碼遵循依賴鄰。請幫助

編輯

這裏是調用模塊中的代碼

接口:

Public Interface ITest 
    Function GetResult() As Boolean 
End Interface 

Class Test 
    Implements ITest 

    Private Function ITest_GetResult() As Boolean Implements ITest.GetResult 
     Dim result As Boolean 
     ...... 
     ...... 
     Return result 
    End Function 
End Class 

編輯2

感謝您的即時回覆。

@Vlad - 我將現有的代碼從VB 6遷移到VB.NET,因此我不應該更改GetResult的訪問修飾符。將它私有會拋出InvalidCastException無法投入類型'System.Object'的對象來鍵入'ITest'

@Dan - 對象類型變量o在很多地方使用,因此我不想改變它。是的,Test以不同的名稱實現了ITest.GetMember。

+0

能否請您提供代碼您的GetResult()方法在ITest界面中如何聲明?我對它的結果類型更感興趣。 – 2011-01-06 14:36:13

回答

2

我沒有用VB.NET工作了很長一段時間,但你可以嘗試是:

讓getResult()方法作爲朋友或公共

如果不工作,那麼嘗試將您的o物體投射到ITest界面

(DirectCast(o, ITest)).GetResult() 

但是您仍然必須將您的方法實現爲朋友或公共接口。

+0

+1,因爲這條直線`(DirectCast(o,ITest))。GetResult()`似乎是Jay的最佳解決方案,因爲由於某種原因o必須保持爲Object。但是你錯了,實際上實現接口的方法可以保持私有。 – MarkJ 2011-01-06 16:50:47

3

我必須有對象o引用 這個,因爲我有其他的代碼遵循 依賴鄰。

你是什麼意思?您是否知道在任何有代碼的地方,您都可以接受Object,它可以接受ITest?這是繼承的一大好處。

至於MissingMemberException:您能否提供ITestTestClass1的定義?如果Test類型使用名稱不同的方法(這在VB.NET中是合法的)實現​​,那麼這可能可以解釋異常 - 儘管這似乎並不是問題出在哪裏。看到您的TestClass1類別的相關代碼尤其會有所幫助。


編輯:根據您的更新,這裏發生了什麼事情。您將VB.NET的後期綁定功能與.NET的概念接口混合在一起。兩者在VB.NET中都得到支持,但它們不是一回事。

所以,當你有一個Object,你可以調用任何方法。這將在運行時解決。但是它必須是一個實際屬於對象類型的方法。在Test的情況下,沒有GetMember功能;只有一個ITest_GetMember函數。所以要利用後期綁定,您需要撥打o.ITest_GetMember(並且此方法將需要公開,我相信)。

這就是說,我強烈建議不要混合接口實現和以這種方式後期綁定。事實上,在這種情況下,如果你真的有一個接口的話,我會建議你不要在後面綁定,在所有的。我真的看不出有什麼理由將你的強類型ITest變量轉換爲Object;正如我前面所說,你可以隨時使用ITestObjectObject是.NET類型層次的;你可以使用任何Object),但你不能總是做使用Object作爲別的東西。

看起來好像你犧牲了你的i變量的可用性(在你發佈的示例代碼中)沒有很好的理由。


編輯2:試想想它,你路過Object引用ByRef?如果是這樣,我想這可能是一個合法的理由(儘管我懷疑你有這樣做的充分理由)。

如果是這種情況,您只需要將您的Object轉換回ITest即可使用ITest的成員。 (見,因爲你已經ITest變量i,這就是爲什麼我一直在質疑你上溯造型到Object

1

實際上,你可以調用接口,而不必強制轉換它,如果你沒有選項嚴格集但是,您將收到嚴格設置爲選項的錯誤。

但是,再次,Option Strict設置爲on的這種做法的正確方法是什麼?

編輯 我得到了答案,這適用於我的場景,在很大程度上適用於上述問題。與我的情況唯一的區別是接口是在一個衛星類中實現的(因此作爲一個程序集加載) 因此,這裏提供了適用於上述問題的代碼解決方案,如果接口在加載的程序集中實現運行。

For Each x In AppDomain.CurrentDomain.GetAssemblies() 
    Dim myType = (From t In x.GetTypes() Where t.IsClass And t.GetInterface("ITest") IsNot Nothing Select t).FirstOrDefault 
    'you can add other criteria inside the linq expression above to match, e.g the assembly version and/or the assembly string (which contains assembly's version) 
    If myType IsNot Nothing Then 
     Dim obj = Assembly.GetAssembly(myType).CreateInstance(myType.FullName) 
     Dim result As Boolean = CType(myType.InvokeMember("ITest_GetResult", BindingFlags.Default Or BindingFlags.InvokeMethod, Nothing, obj, Nothing), Boolean) 
    End If 
Next 
0

這是「裝箱和取消裝箱」(或不裝箱)的副作用。我不記得任何我會推薦的特定資源,但我會閱讀一些博客,詳細介紹將對象類型轉換回來的背後知識。基本上,因爲你使用的是後期綁定,所以VB IDE /編譯器會將你的代碼轉換成代碼,該代碼使用針對該實例類型(即Test)的反射。請參考下面的代碼說明:

Dim o As Object 
o = i '<-- right here is "boxing". its "boxed" up and can be treated 
''as an "Object" object. This allows it to be treated [covariantly][1] 

'' What you typed: 
Dim b As Boolean = o.GetResult() '<--right here it needs to be unboxed 
''in order for the compiler to map the interface implementation. What 
''happens instead is shown below. 

'' What compiled: (after converted back to vb code from IL) 
'' .....keep in mind, o.GetType() returns the same type as 
''GetType(Test), NOT GetType(ITest) 
Dim b As Boolean = o.GetType().InvokeMember("GetResult", 
    BidingFlags.Instance or BidningFlags.InvokeMethod 
    Or BindingFlags, Nothing, o, New Object() {}) 

現在實際的代碼可能有一點不同,我只是接近它來證明這是怎麼回事。從類型對象調用類似的成員只會搜索並執行已聲明的實例成員。運行時不搜索並嘗試映射接口實現(出於性能,安全性和其他許多原因)。我不確定你是否有任何限制,但你真的需要去改變所有使用相同變量的代碼。每個方法調用和屬性獲取/設置都通過反射進行路由。