Languages - DevSource
DevSource: Microsoft Developer Resource DevSource Home Sponsored by Microsoft Home Add Ons Architecture Languages Techniques Using VS Forums
Home arrow Languages arrow Page 2 - Implementing Extension Methods in C#
Implementing Extension Methods in C#
By Paul Kimmel

Rate This Article: Add This Article To:

Implementing Extension Methods in C#
( Page 2 of 3 )

 

Overloading Extension Methods

As is true with regular methods we can overload extension methods too. Notice that in Listing 1 a foreach statement is needed to iterate over a list of items and then Write is called. We can add an overloaded version of Write to the WriteObjectState class. This overloaded version (see Listing 2) is defined to overload IEnumerable. In this way we call Write and the compiler figures out whether the object is a list or a single object. Listing 2 moves the foreach part of Listing 1 to an overloaded Write method.

ADVERTISEMENT

Listing 2: WriteObjectState now contains a method that extends IEnumerable objects, so we can dump lists too.

 public static class WriteObjectState
{
// extension method that writes an object's state
public static void Write(this object obj, TextWriter writer)
{
var formatted = from info in obj.GetType().GetProperties()
let value = info.GetValue(obj, null)
select new {Name=info.Name, Value=value==null?"":value};
Array.ForEach(formatted.ToArray(), r=>
writer.WriteLine(r));
}
// an overloaded extension method that calls write for
// all items in a list
public static void Write(this IEnumerable list, TextWriter writer)
{
foreach(var obj in list)
obj.Write(writer);
}
}

Coding a Generic Extension Method

There is a school of thought that says objects should be self-persisting. For example, a customer class should be able to read and write itself to and from a database. In theory self-persisting objects is a compelling idea. There are some drawbacks. The first is that self-persisting objects have to carry around all of the persistence baggage, and the second is that if a customer self-persists and an order self-persists then what class is responsible for managing persistence when both need to be persisted as part of a transaction? The answer is that some other agent directs choreographs the persistence of both objects as part of a single action and the self-persisting model breaks down.

Extension methods are interesting here. We can use a generic extension method to extend IDataReader so that it looks like a reader knows how to read specific kinds of fields from an IDataReaader. (We could also use extension method to support initializing a whole object, but the fragment in Listing 3 simple knows how to read a single field based on the field name and the type of the field.)

Listing 3: A generic extension method that knows how to read fields from an IDataReader and makes it look like an inhernet capability of the IDataReader itself.

 public static class DataHelper
{
public static T SafeRead<T>(this IDataReader reader,
string fieldName, T defaultValue)
{
try
{
object o = reader[fieldName];
if(o == null || o == System.DBNull.Value)
return defaultValue;
return (T)Convert.ChangeType(o, defaultValue.GetType());
}
catch
{
return defaultValue;
}
}
}

Listing 4: Contains all of the code for the simplpe extension method that uses Reflection and the SafeRead generic method for IDataReader, including an entity class and some ADO.NET code for retrieving the Customer table data.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Data;
using System.Data.SqlClient;
namespace ExtensionMethod
{
class Program
{
static void Main(string[] args)
{
SimpleExtensionMethod();
GenericExtensionMethod();
}
public static void SimpleExtensionMethod()
{
var numbers = new int[]{1,2,3,4,5,6};
var oddsEvens = from num in numbers
let parity = num % 2 == 0 ? "Even" : "Odd"
select new {Number=num, Parity=parity};
oddsEvens.Write(Console.Out);
Console.ReadLine();
}
public static void GenericExtensionMethod()
{
const string connectionString =
"Data Source=BUTLER;Initial Catalog=Northwind;" +        "Integrated Security=True";
List<Customer> list = new List<Customer>();
using(SqlConnection connection =         new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command =           new SqlCommand("SELECT * FROM Customers", connection);
IDataReader reader = command.ExecuteReader();
while(reader.Read())
{
Customer customer = new Customer();
customer.CustomerID =             reader.SafeRead<string>("CustomerID", "");
customer.CompanyName =             reader.SafeRead<string>("CompanyName", "");
customer.City = reader.SafeRead<string>("City", "");
list.Add(customer);
}
}
list.Write(Console.Out);
Console.ReadLine();
}
}
public class Customer
{
public string CustomerID{get; set;}
public string CompanyName{get; set;}
public string City{get; set;}
}
public static class DataHelper
{
public static T SafeRead<T>(this IDataReader reader,
string fieldName, T defaultValue)
{
try
{
object o = reader[fieldName];
if(o == null || o == System.DBNull.Value)
return defaultValue;
return (T)Convert.ChangeType(o, defaultValue.GetType());
}
catch
{
return defaultValue;
}
}
}
public static class WriteObjectState
{
// extension method that writes an object's state
public static void Write(this object obj, TextWriter writer)
{
var formatted = from info in obj.GetType().GetProperties()
let value = info.GetValue(obj, null)
select new {Name=info.Name, Value=value==null?"":value};
Array.ForEach(formatted.ToArray(), r=>
writer.WriteLine(r));
}
// an overloaded extension method that calls write for
// all items in a list
public static void Write(this IEnumerable list, TextWriter writer)
{
foreach(var obj in list)
obj.Write(writer);
}
}
}



 
 
>>> More Languages Articles          >>> More By Paul Kimmel
 



DevSource video
Devsource Video Series
Manipulating Society through Technology
Jeremy Bailenson, Director of the Virtual Human Interaction Lab at Stanford University, talks about virtual reality, avatars, Moore's law, how real world behaviors influence online reality, and societal manipulation through technology!
>> Play video
>> Read article
>> See all videos
DevLife Blog

Julia explores the Robotics Studio! (It's for more than you think.)

MSDev Blog

Messages for Bill Gates!

Make it Work
.NET makes runtime type checking a breeze. See what Peter has to say about it in this week's tips!
News
Microsoft Counts on App Support for Vista
Microsoft has taken pains to demonstrate that Windows Vista will have ample application support.
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.