Bite Size C# – Delegates

A delegate is a form of a type-safe function pointer. More simply put, it is an object that knows how to call a method, i.e. a reference to a method. Delegates are useful as they assist us in writing flexible and extendable applications.

Delegates are useful when using the eventing design pattern also known as the observer pattern. The eventing or observer pattern consists of an object, called the subject or publisher, which maintains a list of dependent objects, called observers or subscribers, and notifies them automatically of a state change in the subject-object by raising an event and then calling a method on the observer objects by using a delegate. We will cover this pattern in more detail when I cover events in a separate post.

For now, let us simply focus on delegates.

So, let us look at an example:


public class KillerRobot
{
	public string Name { get; set; }
}

public class KillerRobotActuator
{
	public delegate void KillerRobotActionHandler(KillerRobot robot); 	//Declare delegate which will act as a
															//signature for methods that can be
															//referenced.

	public void DoAction(string robotName, KillerRobotActionHandler actionHandler)
	{
		var robot = new KillerRobot {Name = robotName	};
		actionHandler(robot);
	}
}

public class RobotActions
{
	public void RobotTalk(KillerRobot robot)
	{
		Console.WriteLine(“{0} is Talking.”, robot.Name);
	}

	public void RobotDance(KillerRobot robot)
	{
		Console.WriteLine(“{0} is Dancing.”, robot.Name);
	}
}

class Program
{
	static void Main(string[] args)
	{
		var robotActuator = new KillerRobotActuator();
		var robotActions = new RobotActions();
		KillerRobotActuator.KillerRobotActionHandler actionHandler = robotActions.RobotTalk;
		actionHandler += robotActions.RobotDance;
		actionHandler += RobotPowerOff;

		robotActuator.DoAction(“The Geek”,actionHandler);
	}

	static void RobotPowerOff(KillerRobot robot)
	{
		Console.WriteLine(“{0} has turned off.”, robot.Name);
	}
}

So, in this basic example we have a class KillerRobotActuator which declares a delegate:

public delegate void KillerRobotActionHandler(KillerRobot robot);

Any method that complies to this signature can then be added to this delegate and in the DoAction method where the following is executed:

actionHandler(robot);

All the methods that have been added to the actionHandler will then be executed.
We can see in the Main method of the Program class that a new KillerRobotActionHandler is declared and three method references are added to it as below:

KillerRobotActuator.KillerRobotActionHandler actionHandler = robotActions.RobotTalk;
actionHandler += robotActions.RobotDance;
actionHandler += RobotPowerOff;

And then finally the DoAction method on KillerRobotActuator is executed, passing in the above declared actionHandler containing references to the three methods:

robotActuator.DoAction(“The Geek”,actionHandler);

All three the methods that are referenced by the actionHandler comply to the signature defined in the delegate declaration in the KillerRobotActuator class. i.e. a void return type and an input parameter of type KillerRobot.
It is also worth mentioning that of the methods referenced, two are contained in a separate class RobotActions and the third is a static method declared in the Program class, so methods from multiple different class locations can be added as long as they comply to the signature of the delegate declares.

 

Bite Size C# – Delegates

Bite Size C# – Generics

Generics refer to the method of creating classes and methods in a way that defers the specification of the type or types associated with the class or method until it is declared and instantiated.

What this means in plain english is that you can define a single class or method that can be utilised with multiple types, thus resulting in less and tidier code.

So let us have a look at an example. Firstly let us look at some code that is not generic. Here we have a class which consist of a list of integers, it has a default constructor as well as two methods, one to add an integer to the list and the other to return the sum of all the integers in the list.

public class KillerRoboticsIntList
{
   public List<int> IntList { get; set; }

    public KillerRoboticsIntList()
    {
        IntList = new List<int>();
    }

    public void Add(int item)
    {
        IntList.Add(item);
    }

    public int Sum()
   {
	int sum;
	foreach(int i in IntList)
	{
	 sum += i;
	}
	return sum;
   }

}

This is a very basic example and can be utilised as follows:

class Program
        {
            public static void Main()
            {
                KillerRoboticsIntList iList = new KillerRoboticsIntList();
		        iList.Add(1);
		        iList.Add(2);
		        iList.Add(3);
		        iList.Add(4);
		        int sum = iList.Sum();
                Console.WriteLine(“Sum = {0}.", sum);

            }
        }

This is very straight forward, however if I would like to use this class with a data type other than int (for example a float or a double) I would need to define a new class for each data type. This can be overcome by utilising Generics. Below is an example of how this can be implemented:

public class KillerRoboticsGenericList<T>
{
   public List GenList<T> { get; set; }

    public KillerRoboticsGenericList()
    {
        GenList = new List<T>();
    }

    public void Add(T item)
    {
        GenList.Add(item);
    }

    public T Sum()
   {
	T sum;
	foreach(T i in GenList)
	{
	 sum += i;
	}
	return sum;
   }

}

The above class can now be defined for various types as seen below:

class Program
        {
            public static void Main()
            {
              KillerRoboticsIntList<int> intList = new KillerRoboticsIntList<int>();
		        intList.Add(1);
		        intList.Add(2);
		        intList.Add(3);
		        intList.Add(4);
		        int sum = intList.Sum();
                Console.WriteLine(“Int Sum = {0}.", sum);

		        KillerRoboticsIntList<double> = new KillerRoboticsIntList<double>();
		        doubleList.Add(0.1);
		        doubleList.Add(2.2);
		        doubleList.Add(3.0);
		        doubleList.Add(1.4);
		        double dSum = doubleList.Sum();
                Console.WriteLine(“Double Sum = {0}.", dSum);

            }
        }

In some cases you might want to put a restriction on the types that can be utilised to implement a generic class of method, this can be achieved by utilising constraints. For example the class we defined above can be restricted to types that implement the IComparable interface by simple changing the first line as follows:

public class KillerRoboticsGenericList<T> where T : IComparable

Some additional examples of constraints are:

where T : Product

This restricts the type of T to an implementation of the class Product or any of its child classes.

where T : struct

This restricts the type of T to the value type struct.

where T : new()

This restricts the type of T to an object with a default constructor.

Multiple Constraints can also be appled at the same time, for example:

 
public class KillerRoboticsGenericList<T> where T : IComparable, new() 

A Generic class can be defined to utilise multiple types, for example:

 
public class KillerRoboticsGenericList<T,U,V>  

It is also worth mentioning that the default c# List class used in the above examples also utilises generics, along with all the other predefined c# collections contained in System.Collections.Generic.

I hope this post has been useful and I will be posting on some additional C# topics, such as Delegates, Lamda Expressions, LINQ, Extension Methods, etc. over the next few months.

Bite Size C# – Generics

Book Review – Robot Builder’s Bonanza

Many books have been written on the topic of robot building, ranging from very basic to extremely complex, but I have seldom come across a book that gets the balance right. Robot Builder’s Bonanza by Gordon McComb hits the sweet spot.

robotbook

The book provides a vast amount of detail on the electronics, mechanics and programming required to build a robot. Concepts like movement (for both wheeled and legged robots), sensors (to make your robot perceive its environment and conditions), the pros and cons of different Micro-controllers, as well as many other actuators (that allow the robot to change its environment in some way) are all covered. 

At the start of each section, a brief introduction to the field is given that includes explanations of key concepts (such as resistors and capacitors in the case of the electronics section) to the tools used (such as drills and screws in the case of the mechanical section). The book includes over 100 projects as examples to illustrate the concepts covered.

The book, in both print and content, is of very high quality. It is very clearly written and provides many diagrams, pictures and schematics, making it easy to understand even the more complex topics covered, for example robotic vision, robotic interpretation of sounds or the choice of which micro-controllers to use as your robots’ brain.

I would very highly recommend Robot Builder’s Bonanza to anyone interested in getting started in robot building or even someone who is currently building robots. It is not just a great book for learning the basics and getting started, but it is also a great reference guide to complex topics as well as a source of inspiration.

As far as Robotics books go this is one of the best, do yourself a favour and pick up a copy today.

Book Review – Robot Builder’s Bonanza

Bite Size C# – DataTable to RecordSet Converter

When working on legacy systems you may sometimes find that a wide variety of technologies have been used, and short of rewriting a huge amount of code the only thing that can be done is to create some functionality to map between the different technologies utilised.

I had a scenario where I had to integrate 2 legacy applications utilising different technologies for database access, one utilised ADODB and the other ADO.NET. Due to time constraints I could not change the underlying code of the systems and rather decided to create a helper class to map an ADO.NET DataTable to an ADODB RecordSet in order to facilitate the integration.

My DTtoRSconvert is a static class that resides in the Core.Data.Help namespace. It contains a static method ConvertToRecordSet that takes a DataTable as a parameter and returns a RecordSet. It also has one static private method TranslateType which is used to map between the DataTable and RecordSet Data types.

Here is the code:

using System.Data;
using System.Reflection;
using ADODB;

namespace Core.Data.Helper
{
    //Helper class that convert ADO.Net DataTables to ADODB RecordSets
    public static class DTtoRSconvert
    {
        public static Recordset ConvertToRecordSet(DataTable inTable)
        {
            var recordSet = new Recordset { CursorLocation = CursorLocationEnum.adUseClient };

            var recordSetFields = recordSet.Fields;
            var inColumns = inTable.Columns;

            foreach (DataColumn column in inColumns)
            {
                recordSetFields.Append(column.ColumnName
                                    , TranslateType(column.DataType)
                                    , column.MaxLength
                                    , column.AllowDBNull
                                          ? FieldAttributeEnum.adFldIsNullable
                                          : FieldAttributeEnum.adFldUnspecified
                                    , null);
            }

            recordSet.Open(Missing.Value
                        , Missing.Value
                        , CursorTypeEnum.adOpenStatic
                        , LockTypeEnum.adLockOptimistic, 0);

            foreach (DataRow row in inTable.Rows)
            {
                recordSet.AddNew(Missing.Value,
                              Missing.Value);

                for (var columnIndex = 0; columnIndex &lt; inColumns.Count; columnIndex++)
                {
                    recordSetFields[columnIndex].Value = row[columnIndex];
                }
            }

            return recordSet;
        }

        private static DataTypeEnum TranslateType(IReflect columnDataType)
        {
            switch (columnDataType.UnderlyingSystemType.ToString())
            {
                case "System.Boolean":
                    return DataTypeEnum.adBoolean;

                case "System.Byte":
                    return DataTypeEnum.adUnsignedTinyInt;

                case "System.Char":
                    return DataTypeEnum.adChar;

                case "System.DateTime":
                    return DataTypeEnum.adDate;

                case "System.Decimal":
                    return DataTypeEnum.adCurrency;

                case "System.Double":
                    return DataTypeEnum.adDouble;

                case "System.Int16":
                    return DataTypeEnum.adSmallInt;

                case "System.Int32":
                    return DataTypeEnum.adInteger;

                case "System.Int64":
                    return DataTypeEnum.adBigInt;

                case "System.SByte":
                    return DataTypeEnum.adTinyInt;

                case "System.Single":
                    return DataTypeEnum.adSingle;

                case "System.UInt16":
                    return DataTypeEnum.adUnsignedSmallInt;

                case "System.UInt32":
                    return DataTypeEnum.adUnsignedInt;

                case "System.UInt64":
                    return DataTypeEnum.adUnsignedBigInt;

                //System.String will also be handled by default
                default: 
                    return DataTypeEnum.adVarChar;
            }
        }
    }
}
Bite Size C# – DataTable to RecordSet Converter

Bite Size C# – XLS File Merger

This will be the last Bite Size C# post revolving around CSV and XLS files (for a while at least). The next one will be on a different and probably a bit more exciting topic.

Today we will look at my XLS File Merger, which resides in the Core.XLS namespace of my Core.dll library. It is a static class with one static method MergeFiles. The purpose of this method is to merge 2 or more XLS files into a single file, i.e. taking the worksheets of 2 or more files and combing them into a single file. The MergeFiles method takes 2 arguments: a list of locations of files to be merged (filePathList) and the destination file that will be created (outputFile).

Here is the code:

using System;
using Microsoft.Office.Interop.Excel;

namespace Core.XLS
{
    public static class XlsFileMerge
    {
        public static void MergeFiles(string[] filePathList, string outputFile)
        {
            var app = new Application {Visible = false};

            app.Workbooks.Add("");
            foreach (var file in filePathList)
            {
                app.Workbooks.Add(file);
            }


            for (var i = 2; i &lt;= app.Workbooks.Count; i++)
            {
                var count = app.Workbooks[i].Worksheets.Count;

                app.Workbooks[i].Activate();
                for (var j = 1; j &lt;= count; j++)
                {
                    var ws = (_Worksheet) app.Workbooks[i].Worksheets[j];
                    if (ws.UsedRange.Rows.Count &lt;= 1) continue;
                    ws.Select(Type.Missing);
                    ws.Cells.Select();


                    var sel = (Range) app.Selection;
                    sel.Copy(Type.Missing);

                    var sheet = (_Worksheet) app.Workbooks[1].Worksheets.Add(
                        Type.Missing, Type.Missing, Type.Missing, Type.Missing
                                                 );
                    sheet.Name = ws.Name;
                    sheet.Paste(Type.Missing, Type.Missing);
                }
            }
            app.Workbooks[1].SaveAs(@outputFile);
            app.Quit();
        }
    }
}
Bite Size C# – XLS File Merger

Bite Size C# – XLS Creator

Today we will look at my XLS Creator Class. It is very similar to my CSV Creator class discussed in an earlier post (BITE SIZE C# – CSV FILE CREATOR), except that it creates a well formed XLS file instead of a CSV file.

It is a static class contained in the Core.XLS namespace and contains 1 static method ExportToExcel. Like the CSV Creator class it uses a generic list of objects to construct a XLS file. The method also takes 2 string values xlsNameWithExt and sheetName.

xlsNameWithExt which is used to define the name and location to save the created XLS file and sheetName which is used to set the sheet name the data will be inserted on.

Here is the code:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Core.XLS
{
  public static class XlsCreator
  {
  public static void ExportToExcel<T>(List<T> list, string xlsNameWithExt, string sheetName)
  {
  var columnCount = 0;

  var StartTime = DateTime.Now;

  var rowData = new StringBuilder();

  var properties = typeof (T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

  rowData.Append("<Row ss:StyleID=\"s62\">");
  foreach (var p in properties)
  {
  if (p.Name.ToUpper() == "ENTITYSTATE" || p.Name.ToUpper() == "ENTITYKEY")
    continue;

  if (p.PropertyType.Name != "EntityCollection`1" && p.PropertyType.Name != "EntityReference`1")
  {
    var type = "String";
    columnCount++;
    rowData.Append("<Cell><Data ss:Type=\"" + type + "\">" + p.Name + "</Data></Cell>");
  }
  else
    break;
  }
  rowData.Append("</Row>");

  foreach (var item in list)
  {
  rowData.Append("<Row>");
  for (var x = 0; x < columnCount; x++) //each (PropertyInfo p in properties)
  {
    var o = properties[x].GetValue(item, null);
    var value = o == null ? "" : o.ToString();
    rowData.Append("<Cell><Data ss:Type=\"String\">" + value + "</Data></Cell>");
  }
  rowData.Append("</Row>");
  }

  var sheet = @"<?xml version=""1.0""?>
    <?mso-application progid=""Excel.Sheet""?>
    <Workbook xmlns=""urn:schemas-microsoft-com:office:spreadsheet""
    xmlns:o=""urn:schemas-microsoft-com:office:office""
    xmlns:x=""urn:schemas-microsoft-com:office:excel""
    xmlns:ss=""urn:schemas-microsoft-com:office:spreadsheet""
    xmlns:html=""http://www.w3.org/TR/REC-html40"">
    <DocumentProperties xmlns=""urn:schemas-microsoft-com:office:office"">
    <Author>MSADMIN</Author>
    <LastAuthor>MSADMIN</LastAuthor>
    <Created>2011-07-12T23:40:11Z</Created>
    <Company>Microsoft</Company>
    <Version>12.00</Version>
    </DocumentProperties>
    <ExcelWorkbook xmlns=""urn:schemas-microsoft-com:office:excel"">
    <WindowHeight>6600</WindowHeight>
    <WindowWidth>12255</WindowWidth>
    <WindowTopX>0</WindowTopX>
    <WindowTopY>60</WindowTopY>
    <ProtectStructure>False</ProtectStructure>
    <ProtectWindows>False</ProtectWindows>
    </ExcelWorkbook>
    <Styles>
    <Style ss:ID=""Default"" ss:Name=""Normal"">
    <Alignment ss:Vertical=""Bottom""/>
    <Borders/>
    <Font ss:FontName=""Calibri"" x:Family=""Swiss"" ss:Size=""11"" ss:Color=""#000000""/>
    <Interior/>
    <NumberFormat/>
    <Protection/>
    </Style>
    <Style ss:ID=""s62"">
    <Font ss:FontName=""Calibri"" x:Family=""Swiss"" ss:Size=""11"" ss:Color=""#000000""
    ss:Bold=""1""/>
    </Style>
    </Styles>
    <Worksheet ss:Name=""" + sheetName + @""">
    <Table ss:ExpandedColumnCount=""" + (properties.Count() + 1) + @""" ss:ExpandedRowCount=""" +
    (list.Count() + 1) + @""" x:FullColumns=""1""
    x:FullRows=""1"" ss:DefaultRowHeight=""15"">
    " + rowData + @"
    </Table>
    <WorksheetOptions xmlns=""urn:schemas-microsoft-com:office:excel"">
    <PageSetup>
    <Header x:Margin=""0.3""/>
    <Footer x:Margin=""0.3""/>
    <PageMargins x:Bottom=""0.75"" x:Left=""0.7"" x:Right=""0.7"" x:Top=""0.75""/>
    </PageSetup>
    <Print>
    <ValidPrinterInfo/>
    <HorizontalResolution>300</HorizontalResolution>
    <VerticalResolution>300</VerticalResolution>
    </Print>
    <Selected/>
    <Panes>
    <Pane>
      <Number>3</Number>
      <ActiveCol>2</ActiveCol>
    </Pane>
    </Panes>
    <ProtectObjects>False</ProtectObjects>
    <ProtectScenarios>False</ProtectScenarios>
    </WorksheetOptions>
    </Worksheet>
    <Worksheet ss:Name=""Sheet2"">
    <Table ss:ExpandedColumnCount=""1"" ss:ExpandedRowCount=""1"" x:FullColumns=""1""
    x:FullRows=""1"" ss:DefaultRowHeight=""15"">
    </Table>
    <WorksheetOptions xmlns=""urn:schemas-microsoft-com:office:excel"">
    <PageSetup>
    <Header x:Margin=""0.3""/>
    <Footer x:Margin=""0.3""/>
    <PageMargins x:Bottom=""0.75"" x:Left=""0.7"" x:Right=""0.7"" x:Top=""0.75""/>
    </PageSetup>
    <ProtectObjects>False</ProtectObjects>
    <ProtectScenarios>False</ProtectScenarios>
    </WorksheetOptions>
    </Worksheet>
    <Worksheet ss:Name=""Sheet3"">
    <Table ss:ExpandedColumnCount=""1"" ss:ExpandedRowCount=""1"" x:FullColumns=""1""
    x:FullRows=""1"" ss:DefaultRowHeight=""15"">
    </Table>
    <WorksheetOptions xmlns=""urn:schemas-microsoft-com:office:excel"">
    <PageSetup>
    <Header x:Margin=""0.3""/>
    <Footer x:Margin=""0.3""/>
    <PageMargins x:Bottom=""0.75"" x:Left=""0.7"" x:Right=""0.7"" x:Top=""0.75""/>
    </PageSetup>
    <ProtectObjects>False</ProtectObjects>
    <ProtectScenarios>False</ProtectScenarios>
    </WorksheetOptions>
    </Worksheet>
    </Workbook>";

  using (var sw = new StreamWriter(xlsNameWithExt))
  {
  sw.Write(sheet);
  }
  }
  }
}
Bite Size C# – XLS Creator

Bite Size C# – XLS to CSV Converter

Let us have a look at my XLS to CSV Converter class today.

It is a static class, which is located in the Core.CSV namespace. It contains one static method CovertExcelToCsv which takes 3 parameters excelFilePath, csvOutputFile and worksheetNumber. The excelFilePath parameter is used to input the source Excel file, csvOutputFile is used to input the destination CSV file and lastly worksheetNumber is used to define which worksheet to convert, as CSV files do not have worksheets only one worksheet can be converted to CSV file at a time. The worksheetNumber parameter has a default value of 1 in the event that no value is passed in.

using System;
using System.Data;
using System.Data.OleDb;
using System.IO;

namespace Core.CSV
{
 public static class XlsToCsvConverter
 {
  public static void CovertExcelToCsv(string excelFilePath, string csvOutputFile, int worksheetNumber = 1)
  {
   if (!File.Exists(excelFilePath)) throw new FileNotFoundException(excelFilePath);
   if (File.Exists(csvOutputFile)) throw new ArgumentException("File exists: " + csvOutputFile);

   // Connection string
   var connectionStr =
    String.Format(
     "Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;IMEX=1;HDR=NO\"",
     excelFilePath);
   var cnn = new OleDbConnection(connectionStr);

   // Get schema information and then data in spreadsheet
   var dt = new DataTable();
   try
   {
    cnn.Open();
    var schemaTable = cnn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
    if (schemaTable != null && schemaTable.Rows.Count < worksheetNumber)
     throw new ArgumentException("The worksheet number requested does not exist.");
    if (schemaTable != null)
    {
     var worksheet = schemaTable.Rows[worksheetNumber - 1]["table_name"].ToString().Replace("'", "");
     var sql = String.Format("select * from [{0}]", worksheet);
     var da = new OleDbDataAdapter(sql, cnn);
     da.Fill(dt);
    }
   }
   catch (Exception ex)
   {
    //Insert logging of exception here
    throw;
   }
   finally
   {
    // Close connection to the spreadsheet
    cnn.Close();
   }

   // Write out CSV data
   using (var wtr = new StreamWriter(csvOutputFile))
   {
    foreach (DataRow row in dt.Rows)
    {
     var firstLine = true;
     foreach (DataColumn col in dt.Columns)
     {
      if (!firstLine)
      {
       wtr.Write(",");
      }
      else
      {
       firstLine = false;
      }
      var data = row[col.ColumnName].ToString().Replace("\"", "");
      wtr.Write(String.Format("{0}", data));
     }
     wtr.WriteLine();
    }
   }
  }
 }
}
Bite Size C# – XLS to CSV Converter

Bite Size SQL – Basic Query Optimisation

How SQL queries are written can have a huge impact on how quickly and efficiently they execute. In this post I will explain some very basic methods that can be used to optimise SQL queries.

  • When writing select queries, only select the columns you need. In general using “SELECT *” is very bad practice.
  • Avoid using sub queries, rather use joins. What is meant by this is instead of using:
        SELECT COLUMNA FROM TABLEA WHERE COLUMNB IS IN (SELECT COLUMNB FROM TABLEB)
        Rather use:
        SELECT COLUMNA FROM TABLEA AS TA INNER JOIN TABLEB AS TB ON TA.COLUMNB = TB.COLUMNB
  • Use WHERE to limit the result set to only what you need. There is no point in pulling 10000 records if you are only looking for records, for example in a certain date range.
  • Use WITH NOLOCK with SELECT queries when feasible, this can prevent deadlocks which can cause serious performance issues. However note that using WITH NOLOCK can result in a non-accurate result set being returned which contains non committed records, so keep this in mind when using. But when querying a production system database this risk might be outweighed by the risk of deadlocks occuring.

One last point on stored procedures, this is not really an optimisation point as much as a best practice point. When developing stored procedures always write them to return result sets of the same dimensions. I have worked on numerous legacy systems were this was not the case and it results in a complete nightmare, especially with projects that utilise an ORM.

Bite Size SQL – Basic Query Optimisation

Bite Size C# – CSV File Creator

Today we will be looking at my CSV Creator class, which is included in my Core.dll library.

It has 1 static method that takes a generic list of objects and a CSV file name. It uses the generic list of objects to construct the CSV file. The properties of the object type contained in the list are used in the creation of the header row of the file. The CSV file name parameter is used to save the created file to disk.

This class in contained in my Core.CSV namespace. Here is the code:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Core.CSV
{
    public static class CsvCreator
    {
        public static void CreateCsvFromGenericList<T>(List<T> list, string csvNameWithExt)
        {
            if (list == null || list.Count == 0) return;

            //get type of objects in list
            Type t = list[0].GetType();
            string newLine = Environment.NewLine;

            using (var sw = new StreamWriter(csvNameWithExt))
            {
                //Create an instance of the class
                object o = Activator.CreateInstance(t);
                //Get all properties from class created, this will be used for CSV header row
                PropertyInfo[] props = o.GetType().GetProperties();

                //Create header row based on properties of class
                foreach (
                    PropertyInfo prop in
                        props.Where(prop => prop.Name.ToUpper() != "ENTITYSTATE" 
                        && prop.Name.ToUpper() != "ENTITYKEY"))
                {
                    sw.Write(prop.Name.ToUpper() + ",");
                }
                sw.Write(newLine);

                //create data rows using each object in list
                foreach (T item in list)
                {
                    foreach (string rowData in from pi in props
                                               where !Convert.ToString(item.GetType()
                                                        .GetProperty(pi.Name)
                                                        .GetValue(item, null)).Contains("Unchanged") &&
                                                     !Convert.ToString(item.GetType().GetProperty(pi.Name)
                                                                           .GetValue(item, null))
                                                             .Contains("System.Data.EntityKey")
                                               select Convert.ToString(item.GetType()
                                                                           .GetProperty(pi.Name)
                                                                           .GetValue(item, null))
                                                             .Replace(',', ' ') + ',')
                    {
                        sw.Write(rowData);
                    }
                    sw.Write(newLine);
                }
            }
        }
    }
}

This class is useful when you simply want to create a CSV file from a generic object list quickly.

Bite Size C# – CSV File Creator

Bite Size C#

As a software developer I believe it is critical to build reusable code when possible. All software engineers have their toolbox of previously written code that they reuse when the need arises. Keeping this in mind I have built a Class Library, that I continually extend, that contains all the reusable functions that I use across multiple projects. I call this my Core.dll and include it in all the projects I work on.

The project contains multiple classes for a variety of functions, anything from string manipulation to file generation. I will be sharing little code bits from this Core library in the Bite Size C# posts.

Today we will look at my StringExtensions class, which falls in my Core.Extensions namespace.

using System;

namespace Core.Extension
{
    public static class StringExtensions
    {
        public static bool Contains(this string source, string toCheck, StringComparison comp)
        {      
            return source.IndexOf(toCheck, comp) >= 0;
        }

        public static string GetLast(this string source, int tailLength)
        {
            return tailLength >= source.Length ? source : source.Substring(source.Length - tailLength);
        }
    }
}

The Class contains 2 methods:

A Contains function that is similar to the built-in string.Contains method except that it takes a StringComparison parameter so that case sensitivity, culture and sort rules can be configured.

A GetLast method that passes back the requested last bit of a string (for example last 4 characters of a string.)

When this class is included in a project the following operations can be performed:

 private static void Main(string[] args)
        {
            string testString = "This is a test string";
            bool test = testString.Contains("STRING", StringComparison.InvariantCultureIgnoreCase);
                //This will return true as ignore case is set


            string resultString = -testString.GetLast(6);
                //This will return "string", the last 6 characters in the string
        }

This class acts as an extension class to the predefined C# string class, so its methods appear in the class method list exactly like the built-in string method do (such as string.Equals or string.Trim).

Bite Size C#