Reputation: 363
I've been writing this out a few different places in my code and I want to create a single, generic function, but I can't quite figure out how.
Here is an example of what I'm doing:
public static string FormatCompaniesAsCSV(ICollection<Company> companies)
{
string csv = "";
foreach(Company c in companies)
{
csv += c.CompanyName + ",";
}
return csv.Substring(0, csv.LastIndexOf(","));
}
The problem is that I have to write essentially the same code if I want to display all company SKUs or all of the factories where this is manufactured. The only thing that changes is the object type and the property I am accessing. What I would like to do is something like the following:
public static string FormatCSV<T>(ICollection<T> elements, string propertyName)
{
string csv = "";
foreach(T element in elements)
{
//I know this next line doesn't work
//this is just a high level conceptualization of what I want to do
csv += element.getPropertyValue(propertyName) + ",";
}
return csv.Substring(0, csv.LastIndexOf(","));
}
I need some way to access the properties of the element in the foreach loop, but I don't really know where to start. I've briefly looked at the System.Linq.Expressions library, but I didn't find quite what I was looking for there.
Am I on the right track? If not, is there a better way to accomplish what I would like to do?
Upvotes: 1
Views: 618
Reputation: 117
The concat with commas can be done in 1 line:
List<string> list = new List<string>() { "Hi", "Old" };
string line = String.Join(",", list.ToArray());
You could also write an extension method (like so)
public static string SuperJoin(string joinCharacter, IEnumerable<string> strings)
{
return String.Join(",", strings.ToArray());
}
Then use Linq to select out just the field from your object that you want to combine. No delegates needed
Upvotes: 0
Reputation: 174299
I suggest you pass in a delegate:
public static string FormatAsCSV<T>(IEnumerable<T> elements,
Func<T, string> converter)
{
string csv = "";
foreach(T element in elements)
{
csv += converter(element) + ",";
}
return csv.Substring(0, csv.LastIndexOf(","));
}
You can call this method like this:
FormatAsCsv(companies, x => x.CompanyName);
FormatAsCsv(factories, x => x.ZipCode + " " + x.City);
You could even create an extension method out of it by adding this
before the type of the first parameter:
public static string FormatAsCSV<T>(this IEnumerable<T> elements,
Func<T, string> converter)
Now you can call it like this:
companies.FormatAsCsv(x => x.CompanyName);
factories.FormatAsCsv(x => x.ZipCode + " " + x.City);
BTW: I changed the type from ICollection<T>
to IEnumerable<T>
as you are only using features of IEnumerable<T>
.
And you can improve the generation of the CSV string:
public static string FormatAsCSV<T>(this IEnumerable<T> elements,
Func<T, string> converter)
{
return elements.Select(x => converter(x)).Aggregate((x, y) => x + "," + y);
}
Upvotes: 4