2011-01-06 50 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() {}) 

现在实际的代码可能有一点不同,我只是接近它来证明这是怎么回事。从类型对象调用类似的成员只会搜索并执行已声明的实例成员。运行时不搜索并尝试映射接口实现(出于性能,安全性和其他许多原因)。我不确定你是否有任何限制,但你真的需要去改变所有使用相同变量的代码。每个方法调用和属性获取/设置都通过反射进行路由。