Page 1 of 1

Convert Generic List to DataSet w/ Extension Method in C#

#1 PsychoCoder   User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1659
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Posted 12 August 2009 - 11:46 AM

Recently there was a discussion in the C# Programmers forum regarding Extension Methods in C#. I know that some might say to use them sparingly, which I do, but I feel there’s still a proper place for them, and they are extremely useful. I use them if, say, I need something like IEnumerable<T> to convert a generic list to a DataSet. For this I went with an Extension method as I didn’t feel I should have to create an entirely new object for a single act like this, thus using an Extension Method for this.

An Extension Method allows me to add a method to an existing object without the need to create a new object. Extension methods need to be defined as static but are called with instance method syntax. An extension method can, like all other method, accept parameters. The main difference is the first parameter in an Extension method is preceded by the this keyword, in this case it will be expecting a parameter of type IEnumerable<T>.

This is how the skeleton of our Extension method will look
using System;
using System.Data;
using System.Collections.Generic;
using System.Reflection;

/// <summary>
/// Extension for IEnumerable to convert a generic List to a DataSet
/// Offers for an option DataTable name to be assigned to the table.
/// Can be called as a normal method for the IEnumerable generic List
/// SAMPLE USAGE:
/// DataSet ds = YourList.ConvertGenericList();
/// DataSet ds = YourList.ConvertGenericList("SomeTableName");
/// </summary>
public static class GenericsToDataSet
{
	
}



NOTE: Extension methods have to be static.

The first thing we will look at will be the Constructor for this Extension method. Remember, most static classes do not have a Constructor, but Extension methods require it in order to extend the base class we’re working with. In the Constructor you will see how the” this” modifier is used with IEnumerable<T>. Our Constructor expects a single parameter (Other than the IEnumerable<T> we’re extending) and that is the name of our resulting DataSet. In our Extension method we have an overloaded constructor as well, making the name of the DataSet optional.

We first check to make sure a list is provided or we throw an ArgumentNullException (in the overloaded constructor we also check for the name parameter). Here’s how the 2 constructors look:

/// <summary>
/// (Overload) Extension method to convert a IEnumerable List<T> To a DataSet
/// </summary>
/// <typeparam name="T">List type that is being converted<typeparam>
/// <param name="list">The list itself that is being converted</param>
/// <param name="name">Name of the DataTable to be added to the DataSet</param>
/// <returns>A populated DataSet</returns>
public static DataSet ConvertGenericList<T>(this IEnumerable<T> list, string name)
{
	if (list == null) 
		throw new ArgumentNullException("list");

	if (string.IsNullOrEmpty(name))
		throw new ArgumentNullException("name");

	DataSet converted = new DataSet(name);
	converted.Tables.Add(newTable(name, list));
	return converted;
}

/// <summary>
/// Extension method to convert a IEnumerable List<T> To a DataSet
/// </summary>
/// <typeparam name="T">List type that is being converted</typeparam>
/// <param name="list">The list itself that is being converted</param>
/// <returns>A populated DataSet</returns>
public static DataSet ConvertGenericList<T>(this IEnumerable<T> list)
{
	if (list == null)
		throw new ArgumentNullException("list");

	DataSet converted = new DataSet();
	converted.Tables.Add(newTable(list));
	return converted;
}



As you can see we call the newTable function. This method also have an overloaded version, accepting the name of the DataTable that is in our new DataSet. Here's those 2 methods:

/// <summary>
/// (Overload) Method for getting and populating the DataTable that
/// will be in the converted DataSet
/// </summary>
/// <typeparam name="T">List type that is being converted</typeparam>
/// <param name="name">Name of the DataTable we want</param>
/// <param name="list">The list being converted</param>
/// <returns>A populated DataTable</returns>
private static DataTable newTable<T>(string name, IEnumerable<T> list)
{
	PropertyInfo[] pi = typeof(T).GetProperties();

	DataTable table = Table<T>(name, list, pi);

	IEnumerator<T> e = list.GetEnumerator();

	while (e.MoveNext()) 
		table.Rows.Add(newRow<T>(table.NewRow(), e.Current, pi));

	return table;
}

/// <summary>
/// Method for getting and populating the DataTable that
/// will be in the converted DataSet
/// </summary>
/// <typeparam name="T">List type that is being converted</typeparam>
/// <param name="list">The list being converted</param>
/// <returns>A populated DataTable</returns>
private static DataTable newTable<T>(IEnumerable<T> list)
{
	PropertyInfo[] pi = typeof(T).GetProperties();

	DataTable table = Table<T>(list, pi);

	IEnumerator<T> e = list.GetEnumerator();

	while (e.MoveNext()) 
		table.Rows.Add(newRow<T>(table.NewRow(), e.Current, pi));

	return table;
}



Here we use the GetEnumerator Method to iterate through the provided Generic list to add a new row to our DataTable for each row in our list. For adding each new row we call newRow, passing it the current selection in the Generic list along with the PropertyInfo for that row, PropertyInfo gives us access to the data type and other attributes to this index of the list. Here's how newRow looks

/// <summary>
/// Method for getting the data from the list then create a new
/// DataRow with the property values in the PropertyInfo being
/// provided, then return the row to be added to the Dataable
/// </summary>
/// <typeparam name="T">Type of the Generic list being converted</typeparam>
/// <param name="row">DatRow to populate and add</param>
/// <param name="listItem">The current item in the list</param>
/// <param name="pi">Properties for the current item in the list</param>
/// <returns>A populated DataRow</returns>
private static DataRow newRow<T>(DataRow row, T listItem, PropertyInfo[] pi)
{
	foreach (PropertyInfo p in pi) 
		row[p.Name.ToString()] = p.GetValue(listItem, null);

	return row;
}



In newTable we call a method Table<T> (This too have an overloaded method which is expecting the name of the DataTable contained in the new DataSet). We use PropertyInfo again in the signature of the method as this will let us know what data type each column in the DataTable must be. These methods merely set up the columns in our new DataTable and operate like this

/// <summary>
/// (Overoad) Method resposible for the generation of the DataTable
/// </summary>
/// <typeparam name="T">Type of the List being converted</typeparam>
/// <param name="name">Name for the DataTable</param>
/// <param name="list">List being converted</param>
/// <param name="pi">Properties for the list</param>
/// <returns></returns>
private static DataTable Table<T>(string name, IEnumerable<T> list, PropertyInfo[] pi)
{
	DataTable table = new DataTable(name);

	foreach (PropertyInfo p in pi)
		table.Columns.Add(p.Name, p.PropertyType);

	return table;
}

/// <summary>
/// Method resposible for the generation of the DataTable
/// </summary>
/// <typeparam name="T">Type of the List being converted</typeparam>
/// <param name="list">List being converted</param>
/// <param name="pi">Properties for the list</param>
/// <returns></returns>
private static DataTable Table<T>(IEnumerable<T> list, PropertyInfo[] pi)
{
	DataTable table = new DataTable();

	foreach (PropertyInfo p in pi) 
		table.Columns.Add(p.Name, p.PropertyType);

	return table;
}  



Ok, so now we have a valid extension method for IEnumerable<T>, but how do we use this? I was hoping you'd ask that. Since it's an extension method we will have access to this new method in Intellisense in Visual Studio, just as if it were an actual part of the Framework. So now lets take a look at using this to convert a Generic list into a DataSet. In this example we will create a simple Generic list which will contain only 2 items, we will then use the Extension we created to convert the list into a DataSet:

public DataSet ToDataSet()
{
	//create a generic list
	List<string> list = new List<string>();

	//add 2 items to our list (In real world this can and probably
	//will be more complex than this simple example
	list.Add("Hello");
	list.Add("World");

	//now create a new DataSet
	DataSet converted = list.ConvertGenericList("TestTable");

	return converted;
}



As you can see Extension Methods can be an invaluable tool in your programming arsenal, it allows us to extend any class we want to make it do what we need it to do. This allows us to accomplish a certain task without having to create a completely new type. You can use Extension Methods to extend a class or an Interface, but you cannot use them to override them (something important to remember when using them). I hope you found this tutorial as informative ad useful as I did from writing it. Happy coding! :)

Is This A Good Question/Topic? 1
  • +

Replies To: Convert Generic List to DataSet w/ Extension Method in C#

#2 GMan_ETC   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 31-December 09

Posted 31 December 2009 - 02:53 PM

View PostPsychoCoder, on 12 Aug, 2009 - 10:46 AM, said:

Recently there was a discussion in the C# Programmers forum regarding Extension Methods in C#. I know that some might say to use them sparingly, which I do, but I feel there’s still a proper place for them, and they are extremely useful. I use them if, say, I need something like IEnumerable<T> to convert a generic list to a DataSet. For this I went with an Extension method as I didn’t feel I should have to create an entirely new object for a single act like this, thus using an Extension Method for this.

An Extension Method allows me to add a method to an existing object without the need to create a new object. Extension methods need to be defined as static but are called with instance method syntax. An extension method can, like all other method, accept parameters. The main difference is the first parameter in an Extension method is preceded by the this keyword, in this case it will be expecting a parameter of type IEnumerable<T>.

This is how the skeleton of our Extension method will look
using System;
using System.Data;
using System.Collections.Generic;
using System.Reflection;

/// <summary>
/// Extension for IEnumerable to convert a generic List to a DataSet
/// Offers for an option DataTable name to be assigned to the table.
/// Can be called as a normal method for the IEnumerable generic List
/// SAMPLE USAGE:
/// DataSet ds = YourList.ConvertGenericList();
/// DataSet ds = YourList.ConvertGenericList("SomeTableName");
/// </summary>
public static class GenericsToDataSet
{
	
}



NOTE: Extension methods have to be static.

The first thing we will look at will be the Constructor for this Extension method. Remember, most static classes do not have a Constructor, but Extension methods require it in order to extend the base class we’re working with. In the Constructor you will see how the” this” modifier is used with IEnumerable<T>. Our Constructor expects a single parameter (Other than the IEnumerable<T> we’re extending) and that is the name of our resulting DataSet. In our Extension method we have an overloaded constructor as well, making the name of the DataSet optional.

We first check to make sure a list is provided or we throw an ArgumentNullException (in the overloaded constructor we also check for the name parameter). Here’s how the 2 constructors look:

/// <summary>
/// (Overload) Extension method to convert a IEnumerable List<T> To a DataSet
/// </summary>
/// <typeparam name="T">List type that is being converted<typeparam>
/// <param name="list">The list itself that is being converted</param>
/// <param name="name">Name of the DataTable to be added to the DataSet</param>
/// <returns>A populated DataSet</returns>
public static DataSet ConvertGenericList<T>(this IEnumerable<T> list, string name)
{
	if (list == null) 
		throw new ArgumentNullException("list");

	if (string.IsNullOrEmpty(name))
		throw new ArgumentNullException("name");

	DataSet converted = new DataSet(name);
	converted.Tables.Add(newTable(name, list));
	return converted;
}

/// <summary>
/// Extension method to convert a IEnumerable List<T> To a DataSet
/// </summary>
/// <typeparam name="T">List type that is being converted</typeparam>
/// <param name="list">The list itself that is being converted</param>
/// <returns>A populated DataSet</returns>
public static DataSet ConvertGenericList<T>(this IEnumerable<T> list)
{
	if (list == null)
		throw new ArgumentNullException("list");

	DataSet converted = new DataSet();
	converted.Tables.Add(newTable(list));
	return converted;
}



As you can see we call the newTable function. This method also have an overloaded version, accepting the name of the DataTable that is in our new DataSet. Here's those 2 methods:

/// <summary>
/// (Overload) Method for getting and populating the DataTable that
/// will be in the converted DataSet
/// </summary>
/// <typeparam name="T">List type that is being converted</typeparam>
/// <param name="name">Name of the DataTable we want</param>
/// <param name="list">The list being converted</param>
/// <returns>A populated DataTable</returns>
private static DataTable newTable<T>(string name, IEnumerable<T> list)
{
	PropertyInfo[] pi = typeof(T).GetProperties();

	DataTable table = Table<T>(name, list, pi);

	IEnumerator<T> e = list.GetEnumerator();

	while (e.MoveNext()) 
		table.Rows.Add(newRow<T>(table.NewRow(), e.Current, pi));

	return table;
}

/// <summary>
/// Method for getting and populating the DataTable that
/// will be in the converted DataSet
/// </summary>
/// <typeparam name="T">List type that is being converted</typeparam>
/// <param name="list">The list being converted</param>
/// <returns>A populated DataTable</returns>
private static DataTable newTable<T>(IEnumerable<T> list)
{
	PropertyInfo[] pi = typeof(T).GetProperties();

	DataTable table = Table<T>(list, pi);

	IEnumerator<T> e = list.GetEnumerator();

	while (e.MoveNext()) 
		table.Rows.Add(newRow<T>(table.NewRow(), e.Current, pi));

	return table;
}



Here we use the GetEnumerator Method to iterate through the provided Generic list to add a new row to our DataTable for each row in our list. For adding each new row we call newRow, passing it the current selection in the Generic list along with the PropertyInfo for that row, PropertyInfo gives us access to the data type and other attributes to this index of the list. Here's how newRow looks

/// <summary>
/// Method for getting the data from the list then create a new
/// DataRow with the property values in the PropertyInfo being
/// provided, then return the row to be added to the Dataable
/// </summary>
/// <typeparam name="T">Type of the Generic list being converted</typeparam>
/// <param name="row">DatRow to populate and add</param>
/// <param name="listItem">The current item in the list</param>
/// <param name="pi">Properties for the current item in the list</param>
/// <returns>A populated DataRow</returns>
private static DataRow newRow<T>(DataRow row, T listItem, PropertyInfo[] pi)
{
	foreach (PropertyInfo p in pi) 
		row[p.Name.ToString()] = p.GetValue(listItem, null);

	return row;
}



In newTable we call a method Table<T> (This too have an overloaded method which is expecting the name of the DataTable contained in the new DataSet). We use PropertyInfo again in the signature of the method as this will let us know what data type each column in the DataTable must be. These methods merely set up the columns in our new DataTable and operate like this

/// <summary>
/// (Overoad) Method resposible for the generation of the DataTable
/// </summary>
/// <typeparam name="T">Type of the List being converted</typeparam>
/// <param name="name">Name for the DataTable</param>
/// <param name="list">List being converted</param>
/// <param name="pi">Properties for the list</param>
/// <returns></returns>
private static DataTable Table<T>(string name, IEnumerable<T> list, PropertyInfo[] pi)
{
	DataTable table = new DataTable(name);

	foreach (PropertyInfo p in pi)
		table.Columns.Add(p.Name, p.PropertyType);

	return table;
}

/// <summary>
/// Method resposible for the generation of the DataTable
/// </summary>
/// <typeparam name="T">Type of the List being converted</typeparam>
/// <param name="list">List being converted</param>
/// <param name="pi">Properties for the list</param>
/// <returns></returns>
private static DataTable Table<T>(IEnumerable<T> list, PropertyInfo[] pi)
{
	DataTable table = new DataTable();

	foreach (PropertyInfo p in pi) 
		table.Columns.Add(p.Name, p.PropertyType);

	return table;
}  



Ok, so now we have a valid extension method for IEnumerable<T>, but how do we use this? I was hoping you'd ask that. Since it's an extension method we will have access to this new method in Intellisense in Visual Studio, just as if it were an actual part of the Framework. So now lets take a look at using this to convert a Generic list into a DataSet. In this example we will create a simple Generic list which will contain only 2 items, we will then use the Extension we created to convert the list into a DataSet:

public DataSet ToDataSet()
{
	//create a generic list
	List<string> list = new List<string>();

	//add 2 items to our list (In real world this can and probably
	//will be more complex than this simple example
	list.Add("Hello");
	list.Add("World");

	//now create a new DataSet
	DataSet converted = list.ConvertGenericList("TestTable");

	return converted;
}



As you can see Extension Methods can be an invaluable tool in your programming arsenal, it allows us to extend any class we want to make it do what we need it to do. This allows us to accomplish a certain task without having to create a completely new type. You can use Extension Methods to extend a class or an Interface, but you cannot use them to override them (something important to remember when using them). I hope you found this tutorial as informative ad useful as I did from writing it. Happy coding! :)


I am trying to understand this example and I have run into a problem with the code. I am receiving a error in the "foreach" statement of the DataTable Table<T> methods. The error is related to the "PropertyInfo" parameter in each of these methods - it says: PropertyInfo does not contain a public definition for 'GetEnumerator'. I checked the Microsoft documentation and it is correct - this assembly doesn't implement GetEnumerator. Is it possible that the write meant to use a different parameter?
Please advise.

Thanks in advance
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1