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.