Home > Programming > Why I won’t need any other GetDelimitedString method in C#

Why I won’t need any other GetDelimitedString method in C#

The various Func<T1, TResult> and Action<T> overloads and lambdas are old stuff in C# and .Net, but how clear one is in them and how fluently one can use it in code is a different topic. Today, in my quest to write a generic GetDelimitedString method, I happened to write a nice little function which uses a Func<>.

You must have faced situations where you have an IList<T> or IEnumerable<T> and you want either a comma delimited string value made up of all the objects in this list, or a string using some delimiting character. e.g. if you have this class –

public class Person {

    public string Name { get; set; }
}

and you have a List<Person>, and you want a comma delimited names of all the persons in this list.

Now I wrote an extension method on the IEnumerable<T> –

		public static string GetDelimitedString<T>(this IEnumerable<T> list, Func<T, string> func, string delimiter)
		{
			var delimitedString = new StringBuilder();
			for (int i = 0, length = list.Count(); i < length; i++)
			{
				var name = func(list.ElementAt(i));

				if (i < length - 1)
				{
					delimitedString
						.Append(name)
						.Append(delimiter)
						.Append(" ");
				}
				else
				{
					delimitedString.Append(name);
				}
			}

			return delimitedString.ToString();
		}

I need to pass in a Func<T, string> because only this particular logic is the variable part in the whole algorithm to get a delimited string. The reason this is the variable logic is because this particular extension method doesn’t know how to extract a string value from an object of type T. One might want to use the Name property of type T, or the FirstName property of type T, or FirstName and LastName properties of T or simply a ToString() method on the object of type T.

So whoever is using this method (the developer) will supply a method (Func<T, string>) to this extension method telling  it how to arrive at a string from a T. So in the above Person example, the method which should be passed to the extension method, must take a Person parameter and return a string, like this –

public string GetName(Person p) {
    return p.Name;
}

which can be represented using a lambda like – p => p.Name assuming p is of type Person. Here’s the actual usage –

[Test]
public void should_convert_a_list_of_ints_to_a_delimited_string()
{
	var names = new List<Person> { new Person {Name = "MW"}, new Person {Name = "BB"} };
	var expected = "MW, BB";

	Assert.That(names.GetDelimitedString(p => p.Name, ","), Is.EqualTo(expected));
}

Another example –

[Test]
public void should_convert_a_list_of_ints_to_a_delimited_string()
{
	var listOfInts = new List<int> { 1, 2, 3 };
	const string expected = "1, 2, 3";

	Assert.That(listOfInts.GetDelimitedString(i => i.ToString(), ","), Is.EqualTo(expected));
}

An even more interesting example is this –

[Test]
public void should_convert_any_list_to_a_delimited_string()
{
	const string delimiter = "";
	const string sungard = "SunGard";
	const string datasystems = "DataSystems";
	const string expected = sungard + " " + datasystems;

	var firstAnonymousType = new { Name = sungard };
	var secondAnonymousType = new { Name = datasystems };
	var list = new List<object> { firstAnonymousType, secondAnonymousType };

	Assert.That(list.GetDelimitedString(o => GetName(o), delimiter), Is.EqualTo(expected));
}

private string GetName(object o)
{
	var anonymousTyped = Cast(o, new {Name = ""});
	return anonymousTyped.Name;
}

private T Cast<T>(object obj, T type)
{
	return (T)obj;
}

If you notice, firstAnonymousType is an anonymous type with a single Name property. Then, I am making a List containing these anonymous types because there is no way in which I can specify a type parameter T (which is of anonymous type) to the List, because well, it is anonymous, isn’t it? 😉 The magic is in the Cast method which is casting an object (of type object) back to an object of type anonymous type. The critical piece of code is in the way the Cast method is called – var anonymousTyped = Cast(o, new {Name = “”})

This above magical piece of code (about casting of anonymous types) came from Tomas Petricek’s article.

One last info. – just by looking at a lambda expression, you won’t be able to figure out if the underlying delegate is an Action<> or a Func<> because in both cases, the lambda looks similar – x => x.Something.

Update: Yesterday, one of my colleagues, Dan modified the code of the above method to a one liner using Linq 🙂 sweet….

public static string GetDelimitedString<T>(this IEnumerable<T> list, Func<T, string> converter, string delimiter)
{
	return String.Join(delimiter, list.Select(converter).ToArray());
}
Advertisements
Categories: Programming
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: