Suppose you write a control subclass that you want people to be able to add to a window layout OR be able to create on the fly. But you want to make sure that when an instance is constructed in code it MUST have a parameterized constructor. However, in order to put an instance on a layout by drag and drop it has to have a no parameter constructor. These two design goals seem very much at odds.
So how do you make this happen ?
Such a control might be like :
Class myControl
Inherits Canvas
Sub Constructor()
End Sub
Sub Constructor(name as string)
self.mName = name
End Sub
Computed Property MyName as string
Function Getter() as string
return mName
End Function
Sub Getter(value as string)
mName = value
End Sub
protected mName as string
end class
We’ll assume that MyName has been exposed as part of the Inspector Behaviour.
But the class definition above would definitely allow you to write code that called either constructor. How to make it so the no parameter constructor can only be used by instances on a layout that, as part of initializing the layout, basically does the following
dim c as new myControl
c.MyName = "whatever value the user set in the inspector"
But there is a trick you can use to know how you have been called. An exception exposes the call stack to you and you can examine that to know if there is a window being initialized that has resulted in your no parameter constructor being called. And so you can make it so a window being initialized can use the no parameter version. In fact to make it so your control can be placed on a layout in the IDE designer it MUST have a no parameter constructor if it has any constructors.
If we make that no parameter constructor read as follows we can make this raise an exception when used improperly outside of a window being constructed. Sorry can’t make the compiler reject it (THAT would be awesome)
Try
Raise New NilObjectException
Catch noe As NilObjectException
Dim stack() As String = noe.Stack
// IF this is an instance created on a layout we should find a
// Window.__Init%%o<Window> in the stack above the call to this Constructor
For i As Integer = 0 To stack.Ubound
If stack(i) = "Window.__Init%%o<Window>" Then
Return
End If
Next
// and if we do not then raise an UnsupportedOperation error
Raise New UnsupportedOperationException
End Try
A window, when being created, calls __Init and so we can tell if we were called by a window being created or not by walking up the call stack. If there is no Window.__Init in the stack then we definitely were not and so can raise an exception to let the coder know that this usage, without a parameter, is only for Layouts and nothing else.