In the previous texts on PrivateObject
(here,
here,
and here)
all examples dealt with simple fields and non-generic types.
Moreover, the examples in the last text were a bit contrived -
at least I have never found the need to access private members of base classes... I think.
However, the solution discussed there will help in one particular example -
accessing protected fields marked with WithEvents in base generic classes.
Let's say that you have code similar to this:
Public Class A
Public Event E()
End Class
Public Class X
Protected WithEvents B As A
Public Sub OnE1() Handles B.E
End Sub
End Class
Public Class Y1
Inherits X
End Class
Public Class Y2
Inherits X
Public Sub OnE2() Handles B.E
End Sub
End Class
No problem accessing B, through PrivateObject, when testing either Y1 or Y2:
<TestMethod()>
Public Sub TestY()
Dim a As New A
Dim y1 As New Y1
Dim y2 As New Y2
Dim y1Accessor As New PrivateObject(y1)
Dim y2Accessor As New PrivateObject(y2)
y1Accessor.SetFieldOrProperty("B", a)
y2Accessor.SetFieldOrProperty("B", a)
. . .
End Sub
However, I often have a situation where X is actually a generic type,
and the WithEvents field is of the type specified in the generic definition
(used, for instance, in command definitions that reference different types of view models):
Public Class X(Of T As A)
Protected WithEvents B As T
Public Sub OnE1() Handles B.E
End Sub
End Class
Public Class Y1
Inherits X(Of A)
End Class
Public Class Y2
Inherits X(Of A)
Public Sub OnE2() Handles B.E
End Sub
End Class
If you try to test this using standard code with PrivateObject:
<TestMethod()>
Public Sub TestY()
Dim a As New A
Dim y1 As New Y1
Dim y2 As New Y2
Dim y1Accessor As New PrivateObject(y1)
Dim y2Accessor As New PrivateObject(y2)
y1Accessor.SetFieldOrProperty("B", a)
y2Accessor.SetFieldOrProperty("B", a)
. . .
End Sub
you'll get the following exception on the second call to SetFieldOrProperty:
System.Reflection.AmbiguousMatchException: Ambiguous match found.
As discussed previously, VB.NET generates hidden properties that are used to manage VB.NET's Handles directives.
Here, we actually have an overridable property B declared in class X, and that property is overridden in class Y2.
But, in the first case, PrivateObject can access it without problems, whereas in the second case, we get the exception...
Actually, at first I thought the problem is entirely due to some special handling of WithEvents / Handles directives in VB.NET,
but the example can be simplified as follows:
Public Class X(Of T As {Class})
Protected Overridable Property X As T
End Class
Public Class Y
Inherits X(Of Object)
Protected Overrides Property X As Object
End Class
<TestMethod()>
Public Sub TestMethodY1()
Dim y As New Y
Dim yAccessor As New PrivateObject(y)
yAccessor.SetProperty("X", 1)
End Sub
And this causes an error too
(but if you drop the generic definition, and use Object instead of T in B's declaration, everything works as expected).
Actually, I think it's some sort of a bug in PrivateObject's implementation...
(If you look at the generated code in dotPeek, for instance, it looks the same in both cases.)
Fortunately, there is a way to get around this - just use PrivateObject with the constructor that takes a PrivateType parameter:
<TestMethod()>
Public Sub TestMethodY1()
Dim y As New Y
Dim yAccessor As New PrivateObject(y, New PrivateType(GetType(X(Of Object))))
yAccessor.SetProperty("X", 1)
End Sub
Happy testing!
Top
|