在VB.NET中使用System.Object类型变量调用Interface方法

时间:2011-01-06 13:53:54

标签: .net vb.net interface object

我有一个方法ITest的接口GetResult()。我有一个类Test,它实现了ITest,从而定义了私有方法GetResult()。

接下来,我在另一个类中创建一个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引用它,因为我有其他代码要依赖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。

4 个答案:

答案 0 :(得分:3)

  

我必须有Object引用   这是因为我有其他代码要遵循   这取决于o。

你是什​​么意思?您是否知道,只要您拥有需要Object的代码,它就可以接受ITest?这是继承的一大好处。

至于MissingMemberException:您能否提供ITestTestClass1的定义?如果Test类型使用具有不同名称的方法实现ITest.GetMember(这在VB.NET中是合法的),那可能可以解释异常 - 尽管这似乎不是问题的确切位置在这里。从TestClass1类别中查看相关代码应该会有所帮助。


修改:根据您的更新,这是正在发生的事情。您将VB.NET的后期绑定功能与.NET的接口概念混合在一起。两者都在VB.NET中得到支持,但它们不是一回事。

所以当你有Object时,可以调用任何方法。这将在运行时解决。但是它必须是一个实际属于对象类型的方法。在Test的情况下,没有GetMember函数;只有ITest_GetMember函数。因此,要使用后期绑定,您需要调用o.ITest_GetMember(此方法需要公开,我相信)。

那就是说,我强烈建议不要以这种方式混合接口实现和后期绑定。事实上,在这样的情况下,我建议不要在所有中绑定晚期,其中你实际上有一个接口。我认为没有充分理由将强类型ITest变量转换为Object类型的变量;正如我之前所说,你可以始终使用ITest作为ObjectObject是.NET类型的 root 层次结构;您可以将任何用作Object),但不能总是这样做的是使用Object作为其他内容。

您似乎无缘无故地牺牲了i变量(在您发布的示例代码中)的可用性。


编辑2 :想一想,您是否正在传递Object个引用ByRef?如果是这样,我想这可能是一个合理的理由(尽管我怀疑你有充分的理由这样做)。

如果是这种情况,您只需将Object投回ITest即可使用ITest的成员。 (请参阅,因为您已经在ITest 拥有 i变量,这就是我继续向Object提问的原因。)

答案 1 :(得分:2)

我很长时间没有使用VB.NET,但你可以尝试的是:

将GetResult()方法设为好友或公开

如果这不起作用,那么尝试将o对象转换为ITest接口

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

但是你仍然需要将你的方法实现为朋友或公共接口。

答案 2 :(得分:1)

如果你没有将Option Strict设置为on,你实际上可以调用界面而不必对其进行类型转换,但是,如果选项strict set设置为on,你将得到错误。

但话又说回来,在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

答案 3 :(得分:0)

这是“装箱和拆箱”(或没有拆箱)的副作用。我不记得我推荐的任何特定资源,但是我会阅读一些博客,详细介绍在Object类型中输入和返回后面的管道。基本上,因为你正在使用后期绑定,所以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() {})

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