# Better way to create objects from strings

I'm looking for a better way to create objects based off of a value of a string.

Consider the following:

Input file:

//each Vehicle type has a list of different options
//whose length varies, I provided a simple case
van*2006*dodge*grand caravan*green~
car*2010*toyota*corolla*red~
truck*2005*toyota*tundra*black~


Classes:

abstract class Vehicle: IVehicle{
public int Year;
public string Make;
public string Model;

...
}

class Van : Vehicle
{
...
}

class Car : Vehicle
{
...
}

class Truck : Vehicle
{
...
}


Program:

static void Main(string[] args)
{
char delimiter = '*';
string currentLine = string.Empty;
List<IVehicle> inventory = new List<IVehicle>();

//Open file
{
{
IVehicle temp;

//Tokenize the line
string[] parts = currentLine.Split(delimiter);

switch(parts[0])
{
case "van":
temp = new Van();
...
break;
case "car"
temp = new Car();
...
break;
case "truck"
temp = new Truck();
...
break;
}

}
}

...
}


My problem with the code is the switch statement. It feels messy and I'm looking for a better way.

• What's a Vechicle? Aug 17, 2011 at 16:09
• have you considered Enum.Parse? Apr 21, 2014 at 3:07

In .Net laguages you can easily instatiate any object given only the full name of the class (=namespace+class name).

Here is a runnable example:

using System;
using System.Reflection;

namespace Test
{

class MsgPrinter
{
public MsgPrinter()
{
System.Console.WriteLine("Hello!");
}
}

class Program
{
static void Main(string[] args)
{
Assembly assembly = Assembly.GetExecutingAssembly();
MsgPrinter printer = assembly.CreateInstance("Test.MsgPrinter") as MsgPrinter;
}
}
}


So in your case it would break down to something like (of course, the names in your parameter file would need to exactly match the class names in your application):

...
string[] parts = currentLine.Split(delimiter);
Vehicle vehicle = Assembly.GetExecutingAssembly().CreateInstance(namespace_name+"."+parts[0]) as Vehicle;
...

• (First-time visitor to this site) I used this as an opportunity to learn about a feature - reflection - that I'd had absolutely no experience with. I don't know what the protocol here is, so rather than add my code to your answer I put it on steven.vorefamily.net/using-reflection-to-read-a-text-file - if I should add it to @ultimA's answer instead, or if this is otherwise inappropriate, please let me know. Aug 19, 2011 at 12:52

Here are a few tips:

1. I would use regular expression (and specifically regular expression groups) to parse strings.
2. Instead of a huge switch/case statement it is better to use a small IDictionary which contains all possible mappings from car type to constructor:

    IDictionary<string, Func<IVehicle>> carBuilder = new Dictionary<string, Func<IVehicle>>();
carBuilder.Add("van", () => { return new Van(); });
carBuilder.Add("car", () => { return new Car(); });
carBuilder.Add("truck", () => { return new Truck(); });


And you can always get an instance of a Vehicle type using:

IVehicle vehicle = carBuilder["van"]();


It is always better to clearly separate concerns:

• Introduce a DTO class called VehicleInfo which will contain all columns of a row in your csv file.

• Introduce a class for parsing csv file named VehicleInfoProvider which has a method:

public IList GetVehicleInfos(string filePath)

It will parse the file using the regular expression and fill all fields of a VehicleInfo class

• Another class that can build specific vehicles based on a VehicleInfo. Lets name it VehicleBuilder. It has a method:

public IVehicle CreateVehicle(VehicleInfo info)

This class would contain the dictionary and will be able to create all possible types of vehicle.

• Using a foreach statement you can parse file rows and create all instances:

    IList<VehicleInfo> vehicleInfos = vehicleProvider.GetVehicleInfos(path);

foreach (var vehicleInfo in vehicleInfos)
{
IVehicle vehicle = vehicleBuilder.CreateVehicle(vehicleInfo.VehicleType);