Abuse of Extension Methods
In the code base I’m working with we have a number of objects which augment existing objects. For instance I have a User object which is generated by my ORM so it looks like
string userName;
string firstName;
string lastName;
int companyID;
int locationID;
In order to display user objects it is useful to have the name of the company and the location which are stored in another table. To limit the amount of stuff being passed around we defined an ExtendedUser which extends User and adds the fields
string companyName;
string locationName;
Creating these extended classes requires passing in a base class and then pulling all the properties off of it and assigning them to the extended class. This is suboptimal because it means that when a new property is added to the bass class it has to be added to the code which extracts the properties in the extended class. To address this I created a method which iterates over the properties in the base class and assigns them to the extended class.
public static void CopyProperties(this object destination, object source, List<string> ignoreList)
{
foreach (var property in destination.GetType().GetProperties())
{
if (source.GetType().GetProperties().Select(p => p.Name).Contains(property.Name) && !ignoreList.Contains(property.Name))
{
var sourceProperty = source.GetType().GetProperty(property.Name);
if (property.CanWrite && sourceProperty.GetType() == property.GetType() && sourceProperty.GetValue(source, null) != null)
property.SetValue(destination, sourceProperty.GetValue(source, null), null);
}
}
}
If you have sharp eyes you’ll notice that I’ve defined this method as an extension method. This allows me to do insane things like
ExpandedClass expandedClass = new ExpandedClass();
expandedClass.CopyProperties(cls);
expandedClass.LocationName = GetLocationNameFromID(cls.LocationID);
expandedClass.CourseName = GetCourseNameFromID(cls.CourseID);
expandedClass.InstructorName = GetInstructorNameFromID(cls.InstructorID);
expandedClass.CompanyName = GetCompanyNameFromID(cls.CompanyID);
I can also do this for any other two classes which share property names.