I was putting together a demo of this concept for a class I am teaching in Port Moresby this week.


Using this technique you can have multiple implemenations of an interface, while the client application can be written to be completely agnositic about the implementation.


Here we use Activator.CreateInstance to late bind the implementation class.


Here’s the interface:


public interface IErrorLog
{
 void LogMessage(string message, string location);
 string DisplayLog(string location);
}


Here’s a text file implementation:


using System;
using System.Text;
using System.IO;


public class LogToFile : IErrorLog{
 public void LogMessage(string message, string location){
  FileStream fs = new FileStream(location, FileMode.OpenOrCreate, FileAccess.Write);
  StreamWriter w = new StreamWriter(fs);
  //Set the file pointer to the end.
        w.BaseStream.Seek(0, SeekOrigin.End); 
        Log(message, w);
  w.Close();   //Close the writer and underlying file.    
 }


 public string DisplayLog(string location){
        FileStream fs = new FileStream(location, FileMode.OpenOrCreate, FileAccess.Read);
        StreamReader r = new StreamReader(fs);
        r.BaseStream.Seek(0, SeekOrigin.Begin);
        StringBuilder sb = new StringBuilder();
  //While not at the end of the file, write to standard output.    
  while (r.Peek() > -1) {
   sb.Append(r.ReadLine());
   sb.Append(“\n”);
  }
        r.Close();
        return sb.ToString();
 }


 private void Log(string logMessage, StreamWriter w){
  w.WriteLine(“{0}, {1}, {2}”, DateTime.Now.ToString(“d/M/yyyy”), DateTime.Now.ToString(“HH:mm”), logMessage);
  w.Flush();
 }
 
}


 


Here’s a database implementation:


using System;
using System.Data;
using System.Data.SqlClient;


public class LogToDB : IErrorLog{
 public void LogMessage(string message, string location){
  SqlConnection cn = new SqlConnection(location);
  cn.Open();
  Log(message, cn);
  cn.Close();
 }


 public string DisplayLog(string location){
  SqlConnection cn = new SqlConnection(location);
  SqlDataReader dr;
  SqlCommand cmd = new SqlCommand();
  string strLog = “”;
  cn.Open();
  cmd.CommandText = “select * from LogTable”;
  cmd.Connection = cn;
  dr = cmd.ExecuteReader();
  while (dr.Read()){
   strLog = strLog + Convert.ToDateTime(dr[0]).ToString(“d/M/yyyy”)
    + “, ” + Convert.ToDateTime(dr[1]).ToString(“HH:mm”)
    + “, ” + dr[2].ToString() + “\n”;
   }
  cn.Close();
  return strLog;
 }


 private void Log(string logMessage, SqlConnection cn){
  try{
   SqlCommand cmd  = new SqlCommand();
   cmd.CommandText = “INSERT INTO LogTable(LogDate, LogTime, LogMessage)”
    + ” VALUES(‘” + System.DateTime.Now.ToString(“M/d/yyyy”)
    + “‘, ‘”
    + DateTime.Now.ToShortTimeString() + “‘, ‘”
    + logMessage + “‘)”;
   cmd.Connection = cn;
   cmd.ExecuteNonQuery();
  }
  catch (SqlException eException) {
   foreach(SqlError eErr in eException.Errors){
    System.Windows.Forms.MessageBox.Show(eErr.Message);
   }
  }
  
 }
}


 


Here’s the app.config file, where we can specify which implementation or client will spin up:


<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
 <appSettings>


   <add key=”Type”
     value=”LogToDB”/>
   <add key=”Location”
     value=”Data Source=.;Integrated Security=SSPI;Initial Catalog=LogDB”/>


  
   <!–
 <add key=”Type”
  value=”LogToFile”/>
 <add key=”Location”
  value=”c:\testlog.txt”/>
–>
 </appSettings>
</configuration>


And here’s out client application.  Note there is no hard coding of any implementation classes here.  Beauty, eh?



        public IErrorLog ErrLog;
        public string LogLocation;


        private void Form1_Load(object sender, EventArgs e)
        {
            string logType = ConfigurationManager.AppSettings[“Type”];
            LogLocation = ConfigurationManager.AppSettings[“Location”];
            //late binding
            ObjectHandle handle = Activator.CreateInstance(
                “WindowsApplication1”, logType);
            ErrLog = handle.Unwrap() as IErrorLog;
        }


        private void btnLogMessage_Click(object sender, System.EventArgs e)
        {
            ErrLog.LogMessage(txtMessage.Text.ToString(), LogLocation);
        }


        private void btnDisplayLog_Click(object sender, System.EventArgs e)
        {
            MessageBox.Show(ErrLog.DisplayLog(LogLocation));
        }