How to call a member through its parent's type that shadowed a parent class implementation
This is a challenging one that got me stumped while I was coding today. Suppose I am running the Sub Test1()
and Test2()
and would like to print out the value of the Shadows
method of the instance of the object I am passing in to TestCall()
(see below - it is clearer) using the following restrictions:
- Can't change the contents of
Class A
,B
, andC
- Can't change
Sub Test1()
andSub Test2()
- TestCall() can't have an
if
,select case
etc. statement that tries to figure out the type of the argument passed in and then doCType(o, <C or B>).Method()
. Suppose there are an infinite number of classes likeB
andC
all of which inherit fromA
orB
orC
and shadowMethod
- You can't change the attributes of Subs (i.e. you can't change
Shadows
toOverridable/Overrides
)
I would like to dynamically do the equivalent of CType(o, C).Method()
and print out C.Method
for Test1 and then dynamically do the equivalent of CType(o, B).Method()
and print out 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
You problem comes from the fact that if you use the keyword Shadows
you create a new method with the same name that hides the original method, the inverse of overriding an overridable (virtual) method.
The only way that I can think of to solve this dynamically is to find out the declaring type, query that type for existing methods of a certain signature and then call that method.
If this is what you are after, the following code for TestCall (sorry, in C#, but you tagged your question with C#) will do. The only thing you need to know is the name of the method, which you had to know in the original situation also.
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
Another way to do this as I discovered a few days ago WITHOUT reflection:
Public Sub TestCall(ByVal someAorBorC as A)
Convert.ChangeType(someAorBorC, someAorBorC.GetType()).Method()
End Sub
精彩评论