Object Instantiation in C#. Part V Just Don't Do It

There are many ways to approach object instantiation. In this article we'll cover a few of the patterns used to instantiate objects. In this final article in the series, we'll be looking at how avoid instantiation altogether.

Part V. Avoiding It. 

In Part I of this two-part article, we talked about basic instantiation and different way constructors can work.  In Part II we looked at using factory methods.  In Part III we looked at abstract factories.  In Part IV we took a brief look at the builder pattern  and in this final article in the series, we'll be looking at how avoid instantiation altogether.

The Initializer.

There may be situations where we are writing libraries and need to be sure we are not vulnerable to attack.  If we expose instantiation to the consumer of our library they can keep instantiating new objects until we run out of memory.  The way to avoid this is to just not allow instantiation at all.  In order to do this, we'll just consume interfaces with setters on them.

If we define an interface with settable attributes:

  1. interface IGetterSetter  
  2. {  
  3.     string Prop1 { getset; }  
  4.     string Prop2 { getset; }  
  5. }

We can then create a class for initializing an object that consumes this interface instead of having a factory or a builder:

  1. internal class PropertySetterBase  
  2. {  
  3.     public PropertySetterBase() { }  
  4.   
  5.     public virtual void Initialize(IGetterSetter target)  
  6.     {  
  7.         target.Prop1 = string.Empty;  
  8.         target.Prop2 = string.Empty;  
  9.     }  
  10. }

The cool thing is that we don't deal with any kind of memory allocation at all because we are not instantiating any objects at all.  Because we are not allowing the consumer of this library to allocate memory we have a bit more control over what's happening.

On the consumer's side, they would "new-up" a class implementing our interface and use the initializer object to initialize the state.

  1. public class GetterSetter : IGetterSetter  
  2. {  
  3.     private string  
  4.         m_prop1,  
  5.         m_prop2;  
  6.   
  7.     public string Prop1  
  8.     {  
  9.         get { return m_prop1; }  
  10.         set { m_prop1 = value; }  
  11.     }  
  12.   
  13.     public string Prop2  
  14.     {  
  15.         get { return m_prop2; }  
  16.         set { m_prop2 = value; }  
  17.     }  
  18. }

And the consumer of our library would initialize their object by passing it to our initializer.  If we implement the initializer as a proveder pattern (a static class exposing the functionality of a base class through a common interface or base object) we will have no points where the user of our library will be able to instantiate objects:

Here is an specific implementation of our property setter:

  1. internal class PropertySetter: PropertySetterBase  
  2. {  
  3.     public PropertySetter()  
  4.    {  
  5.         m_prop1val = "Default Value 1";  
  6.         m_prop2val = "Default Value 2";  
  7.     }  
  8.   
  9.     private string  
  10.         m_prop2val,  
  11.         m_prop1val;  
  12.   
  13.     public string Prop1val  
  14.     {  
  15.         get { return m_prop1val; }  
  16.         set { m_prop1val = value; }  
  17.     }  
  18.   
  19.     public string Prop2val  
  20.     {  
  21.         get { return m_prop2val; }  
  22.         set { m_prop2val = value; }  
  23.     }  
  24.   
  25.     public override void Initialize(IGetterSetter target)  
  26.     {  
  27.         target.Prop1 = m_prop1val;  
  28.         target.Prop2 = m_prop2val;  
  29.     }  
  30. }

And here is our initialization provider:

  1. public static class InitializationProvider  
  2. {  
  3.     private static PropertySetterBase m_base = new PropertySetter();  
  4.   
  5.     public static void Initialize(IGetterSetter target)  
  6.     {  
  7.         m_base.Initialize(target);  
  8.     }  

So now, we have effectively avoided instantiation by providing an interface for initialization and a provider to initialize the instance of the object so the user of our class library will instantiate their classes normally and pass them to the InitializationProvider for initialization:

  1. // this instantiation would be performed in the consuming assembly  
  2. // and we would just get passed a reference in the InitializationProvider.Initialize() method  
  3. GetterSetter objSix = new GetterSetter();  
  4. InitializationProvider.Initialize(objSix); 

Well, that's about it for object instantiation.  I hope you found this series of articles informative.

Until next time,
Happy coding