essay on programming languages, computer science, information techonlogies and all.

Friday, July 5, 2019

Create instance of Type dynamically in C#

When applying RAII, constructor tends to have arguments to be fully autonomous afterward. When combined with factory method, there can be number of if-else with "new" and arguments like below pseudo code.

interface IWish
{
  void MakeTrue();
}

class EscapeCave : IWish
{
  public EscapeCave( string master, int nTh, string target ) {  ...  }
  public void MakeTrue() { ... }
}

class BecomePrince : IWish
{
  public BecomePrince( string master, int nTh, string target ) {  ...  }
  public void MakeTrue() { ... }
}

class BecomeHuman : IWish
{
  public BecomeHuman( string master, int nTh, string target ) {  ...  }
  public void MakeTrue() { ... }
}

class Genie
{
  static public IWish Create( string wish, string master, int nth, string target )
  {
    if( wish == "enscape cave" )
    {
      return new EscapeCave( master, nth, target );   // code repetition and become tedious and smelly 
    } 
    else if( wish == "become prince" )
    {
      return new BecomePrince( master, nth, target );
    } 
    else if( wish == "become human" )
    {
      return new BecomeHuman( master, nth, target );
    }  
    
    throw new ArgumentException( "Not supported wish" );
  }
}
To remove code repetition - "new" and arguments, Type can be used with System.ComponentModel.TypeDescriptor.CreateInstance(). Note that the Type should have same constructor - same number of arguments and types. It may be too restrictive but sometimes it is desirable as only difference should be differenct behaviour with same arguments.

class Genie
{
  static public IWish Create( string wish, string master, int nth, string target )
  {
    var typeDict = new Dictionary
    {
      { "enscape cave", typeof(EscapeCave) },
      { "become prince", typeof(BecomePrince) },
      { "become human", typeof(BecomeHuman) },   // genie can add its capable wish by simply adding line in here 
    };
    var typeWish = typeDict[ wish ];

    return (IWish)System.ComponentModel.TypeDescriptor.CreateInstance(
                provider: null, // reflection
                objectType: typeWish,
                argTypes: new Type[] { typeof(string), typeof(int), typeof(string)},
                args: new object[] { master, nth, target }  
    }
}