Introduction
In the vast majority of times when we are coding an application, we use the
keyword
"
new
" to instantiate an object, as shown below:
Dim obj As New AnyObject
In this article we will see two other ways on how to <code>dynamically
instantiate objects without using the keyword "new
". Background
In a project that I recently participated one of the requirements was to instantiate objects dynamically based System.Types
external to the application.
It was a UserControl
whose purpose was to display in a PropertyGrid
properties of the instantiated object so that only the properties modified by the user in the PropertyGrid, were persisted and subsequently reapplied to the object whenever a new instance of it was created.
The System.Type
to be loaded was provided by the user by informing the assembly
location on disk and the System.Type
to instantiate.
During the tests phase, I've used other assemblies created by me in other projects and also assemblies created by others to make sure it was actually working properly regardless of the class.
During this period, I found some situations in which the instantiation via reflection would not work.
Instantiating through reflection
This type of instantiation is widely used by most programmers who need to dynamically create instances of System.Type 's external to the application.
By using Assembly.CreateInstance(string)
to instantiate a type all the instantiation process occurs normally as if you were using the keyword "new
", that is the constructor of the class is executed and all its fields gets initialized properly.
Dim obj1 As Object = _assembly.CreateInstance("MyExternalAssembly.AnyObject")
In the example above we are instantiating a class called "AnyObject
" on the assembly called "MyExternalAssembly
".
In this case you must provide a string with the full name of the System.Type
including the assembly name and namespace (if any), and the name of the class also it must exist in the _assembly
object, otherwise the instantiation does not occur.
Note: Internally after check if the provided System.Type
string exists in the loaded assembly
, it runs the Activator.CreateInstance(<span>System.Type)</span>
method that returns the instance to the caller.
Instantiating through Serialization/Deserialization
I decided tocall this kind of instantiation as "serialization / deserialization" due to the fact that its being used internally in the .Net Framework to deserialize WCF DataContracts
.
For a few times during the testing phase in the project I participated in, I came across situations where logic in the constructor of the class were preventing the instantiation of the object, especially when it was a commercial component whose licensing mechanisms were located in the constructors of the class and were firing exceptions when licensing rules were violated.
Note: In my opinion a good mechanism for licensing and validation must rely not only on the constructor of a class, but also in key methods of the class, and other classes internal to it.
In cases like this instantiating a class by using Reflection is not possible since via Reflection and also through the keyword
"new
", the constructor always runs during instantiation, preventing it from complete.
By analyzing the .Net framework code through Reflector, I found that the WCF's DataContracts
when deserializing an object were never invoking any class's constructors, as well as their fields were not initialized with "default" values that eventually were defined on it.
The reason why the fields are not initialized makes sense. From what I understand is a way to gain performance, since during deserialization - after object creation - these fields will receive different values other than the "Defaults", that way it doesn't make any sense if they were assigned twice, once with their "default" values ??and another with the values ??of serialization.
I still do not understand why the constructor is not invoked, perhaps for performance reasons as well? I do not know ...
Below is the code that does the instantiation without running the constructors or initializing fields:
Dim type = _assembly.GetType("MyExternalAssembly.OtherObject")
Dim obj1 As Object = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type)
Note that the method GetUninitializedObject()
takes a System.Type
that can be a System.Type
from an existing class in the assembly itself or an external assembly, however the external assembly should be previously loaded.
In the example above we use a System.Type
from an assembly external to the application, whose constructor throws an InvalidOperationException
, therefore we can never instantiate an object of this class if we use the standard instantiation by using the keyword "new" or a instantiation via Reflection
Using the source code
In the solution of the source code of this article there are two projects, a Class Library
and a Windows Form Application
.
The "MyExternalAssembly" is a Class Library
which has two classes, one is a class called "AnyObject" that allows any instantiation mentioned in this article to be used, the other class is called "otherObject" which is a class whose default constructor fires one exception, therefore it can be instantiated only by using the process "serialization/deserialization" presented here.
The Project PropertyInspector
is a Windows Forms Application
that allows you to select an external assembly - in this case the assembly MyExternalAssembly - and display your fields in a PropertyGrid, as follows:
Summary
The purpose of this article is to show to beginners alternative ways to instantiate objects and not neither to elect the best way to instantiate an object nor the one that is "more correct".
Perhaps there are other ways to instantiate objects in .NET I may not know yet, if you do, please, feel free to share it with us by using the session "Comments and Discussions".
Depending on usage, one method may be more advantageous than the other in terms of gains in performance, usability, etc.