Question How to cancel class' construction?

VBobCat

Well-known member
Joined
Sep 6, 2011
Messages
137
Location
S?o Paulo, Brazil
Programming Experience
3-5
Hello people,

I have a class which is constructed by a Sub New with parameters.
In this sub, these parameters are used to query a database in search of data that will define new class' properties.
Though unlikely, it may happen that the query returns no elements with such combination defines the entity my class represents.
In this case, I would like the class' construction to be cancelled, so that when program calls
VB.NET:
Dim NewClass as New MyClass(parameters)
or
VB.NET:
Dim NewClass as MyClass
NewClass = New MyClass(parameters)
then MyClass won't be instantiated and NewClass will remain as Nothing, which I shall test and tell user that he cannot proceed without going back and another part of the app in order to insert data that defines that entity.
Is that possible?

Thank you very much.
 
There are a few problems with what you just posted....

In this sub, these parameters are used to query a database in search of data that will define new class' properties. Though unlikely, it may happen that the query returns no elements with such combination defines the entity my class represents.

That's just not possible. You cannot define properties of a class conditionally at run time. Think of a chair. A chair has 4 legs. You cannot decide that the chair has only one leg unless it is in fact a 1 legged chair, in which case it never had 4 legs to begin with. How many legs does your chair have?

In this case, I would like the class' construction to be cancelled, so that when program calls [...] then MyClass won't be instantiated and NewClass will remain as Nothing, which I shall test and tell user that he cannot proceed without going back and another part of the app in order to insert data that defines that entity.
Is that possible?

No that is not possible. What you can do however is give the properties in your class a null value if somehow you receive no data. Then your application that uses the class must determine if there is data or not.
 
Your constructor should throw an exception if it can't complete successfully. You can Try-Catch the attempt to create the instance. If construction fails no instance is created and variable remains Nothing.
 
I thank you for both answers, since I've learned that instancing a class is not an operation that can be simply cancelled. So there are two alternatives:
1. The class can show through its properties that its expected content is not properly fulfilled, and that can be tested by invoking procedure.
2. The constructor can thwart itself throwing an exception, that must be properly catched by invoking procedure.
Now I will decide which approach works better for me. Is there significant difference in terms of performance?
 
Your constructor should throw an exception if it can't complete successfully. You can Try-Catch the attempt to create the instance. If construction fails no instance is created and variable remains Nothing.

Isn't that risky/ugly though? You don't want your class to return a null reference that will throw plenty of exceptions in your client application. I always try to keep classes self contained, I don't like them oozing exceptions on all sides... My point being that there really is no good reason to do what the OP wants to do here. Rule #1 of any computer input is to validate it properly. Exception are expensive performance wise, sometimes they will actually cut down on the time needed to validate an input, but most times not.
 
Isn't that risky/ugly though? You don't want your class to return a null reference that will throw plenty of exceptions in your client application. I always try to keep classes self contained, I don't like them oozing exceptions on all sides... My point being that there really is no good reason to do what the OP wants to do here. Rule #1 of any computer input is to validate it properly.

I was working on it right now. I decided to add a boolean field named Complete to my class, first set to False by the constructor, which will only turn it into True if all required data could be gathered.

An explanation is needed: the data scenario I have to deal with is somewhat complex, because it doesn't rely only on input that the very user supplied just before starting the operation I've described. It gets also data stored in other moments in the past, by other kinds of operations. It is very likely that all needed information will be present, but there are some uncommon situations where they won't, and that will require the user to take the proper measures. One of the aims of my application is to make this warning.

Then, wether using class' properties as signal of clearance, or throwing an exception, the calling procedure would do the same, in case of failure on building the class: warn the user, dispose the class, and iterate, that is, get the next record of data, in order to possibly construct a new class and use it if it is complete, or properly formed. That is, almost all the records will be properly processed by MyClass and by the procedure that instatiates and invokes it. For the few cases it fails, it is enough to tell the user.

Then again, my decision on using a boolean field is based on something I just suspected, for I have no knowledge about how .NET runtime deals with exceptions. But what I suspected is said so:

Exception are expensive performance wise, sometimes they will actually cut down on the time needed to validate an input, but most times not.

So I'd rather not to deal with exceptions, even if I'm able to catch them properly.

Thank you again!
 
Isn't that risky/ugly though? You don't want your class to return a null reference that will throw plenty of exceptions in your client application. I always try to keep classes self contained, I don't like them oozing exceptions on all sides... My point being that there really is no good reason to do what the OP wants to do here. Rule #1 of any computer input is to validate it properly. Exception are expensive performance wise, sometimes they will actually cut down on the time needed to validate an input, but most times not.
A few quotes from design guidelines:
Do report execution failures by throwing exceptions. If a member cannot successfully do what it is designed to do, that should be considered an execution failure and an exception should be thrown.
Do throw exceptions from instance constructors if appropriate.
If a member (including a constructor member) may throw an exception you must take that into consideration in calling code by catching the exception if appropriate.
If a variable reference may be a null reference (Nothing) you must also handle that appropriately in code, it is easy to validate 'If something Is Nothing' should that be a possibility.
Members throwing exceptions and members returning Nothing are both VERY common in all code.

If you can validate input before using the constructor, fine, but that may not be possible, and the input may be valid and even still the constructor may not be able to fulfill its task based on exceptional conditions - if so it should absolutely throw an exception. In .Net libraries you will also find an endless list of members that will validate parameter input and if arguments are not found valid they will throw an exception, you may have seen for example ArgumentNullException and ArgumentOutOfRangeException thrown.
 
It sounds to me like you should not be using a constructor but rather a factory method. You should just define a constructor as you normally would, i.e. it receives parameter values and assigns them to the appropriate properties. There's basically no logic. Your factory method is the one that implements the logic to decide whether an instance can be created or not. If it can then it invokes the constructor and if it can't then it returns a null reference, e.g.
Public Class Thing

    Public Property Name As String

    Private Sub New(name As String)
        Me.Name = name
    End Sub

    Public Shared Function Create() As Thing
        Dim newThing As Thing = Nothing
        Dim name As String = GetName()

        If name IsNot Nothing Then
            newThing = New Thing(name)
        End If

        Return newThing
    End Function

End Class
Note that the constructor is Private so it cannot be invoked directly anywhere but within the Thing class. That means that the only way to create a Thing object is to call the Shared Create method. That method will either return a Thing object or Nothing, so you can easily check the result to see if it worked or not without having to throw an exception.
 
I am proud to say that I was thinking in that direction: I imagined a shared function capable to test wether there are conditions to create a new instance of its own parent class. Then I thought that it was going to duplicate a lot of queries needed to set class' properties, so the best would be that this shared function was able to go further and create the class if it was possible. Then again, I was not sure if a class' shared function could create a new instance of its own base class, but I was going to try it. Your message endorses it as the best available option. Thank you very much!
 
Back
Top