如何通过隐藏父类实现的父类型调用成员

时间:2011-08-03 22:19:35

标签: c# .net vb.net

这是一个具有挑战性的问题,让我在今天编写代码时感到难过。假设我正在运行Sub Test1()Test2(),并希望打印出我传入的对象的实例Shadows方法的值使用以下限制TestCall()(见下文 - 更清楚):

  1. 无法更改Class ABC
  2. 的内容
  3. 无法更改Sub Test1()Sub Test2()
  4. TestCall()不能有ifselect case等语句,试图找出传入的参数的类型,然后执行CType(o, <C or B>).Method()。假设有无数个类,例如BC,所有类都继承自ABC和阴影Method < / LI>
  5. 您无法更改Subs的属性(即您无法将Shadows更改为Overridable/Overrides
  6. 我想动态执行等效的CType(o, C).Method()并打印出C.Method用于Test1,然后动态执行等效的CType(o, B).Method()并打印出B.Method

    <TestFixture()> _
    Public Class Test
    
        <Test()>
        Public Sub Test1()
            Dim o As A = New C
            TestCall(o)  '<-- THIS SHOULD PRINT "C.Method"
        End Sub
    
        Public Sub Test2()
            Dim o As A = New B
            TestCall(o)  '<-- THIS SHOULD PRINT "B.Method"
        End Sub
    
        Public Sub TestCall(ByVal o as A)
              o.Method() 
        End Sub
    
        Class A
            Public Sub Method()
                Console.WriteLine("A.Method")
            End Sub
        End Class
    
        Class B
            Inherits A
    
            Public Shadows Sub Method()
                Console.WriteLine("B.Method")
            End Sub
        End Class
    
        Class C
            Inherits B
    
            Public Shadows Sub Method()
                Console.WriteLine("C.Method")
            End Sub
        End Class
    End Class
    

2 个答案:

答案 0 :(得分:2)

你的问题来自这样一个事实:如果你使用关键字Shadows,你创建一个与隐藏原始方法相同名称的新方法,即覆盖可覆盖(虚拟)方法的反转。

我能想到动态解决这个问题的唯一方法是找出声明类型,查询某个签名的现有方法的类型,然后调用该方法。

如果这就是您所追求的,那么TestCall的以下代码(对不起,在C#中,但您使用C#标记了您的问题)将会这样做。您唯一需要知道的是方法的名称,您在原始情况下也必须知道。

public void TestCall(A someAorBorC)
{
    // store declaring type
    Type T = someAorBorC.GetType();

    // find shadowed method
    var method = (from m in T.GetMethods()
                 where m.DeclaringType == T
                 && m.Name == "Method"
                 select m).SingleOrDefault();
    if (method == null)
        throw new Exception("Method 'Method' not found in declaring type");

    // call method
    method.Invoke(someAorBorC, null);
}

// Console:
C.Method
B.Method

答案 1 :(得分:0)

另一种方法,就像我几天前发现的那样没有反思:

Public Sub TestCall(ByVal someAorBorC as A)
    Convert.ChangeType(someAorBorC, someAorBorC.GetType()).Method()
End Sub