I'm experimenting with generics and I'm trying to create structure similar to Dataset class.
I have following code
public struct Column<T>
{
T value;
T originalValue;
public bool HasChanges
{
get { return !value.Equals(originalValue); }
}
public void AcceptChanges()
{
originalValue = value;
}
}
public class Record
{
Column<int> id;
Column<string> name;
Column<DateTime?> someDate;
Column<int?> someInt;
public bool HasChanges
{
get
{
return id.HasChanges | name.HasChanges | someDate.HasChanges | someInt.HasChanges;
}
}
public void AcceptChanges()
{
id.AcceptChanges();
name.AcceptChanges();
someDate.AcceptChanges();
someInt.AcceptChanges();
}
}
Problem I have is that when I add new column I need to add it also in HasChanges property and AcceptChanges() method. This just asks for some refactoring.
So first solution that cames to my mind was something like this:
public interface IColumn
{
bool HasChanges { get; }
void AcceptChanges();
}
public struct Column<T> : IColumn {...}
public class Record
{
Column<int> id;
Column<string> name;
Column<DateTime?> someDate;
Column<int?> someInt;
IColumn[] Columns { get { return new IColumn[] {id, name, someDate, someInt}; }}
public bool HasChanges
{
get
{
bool has = false;
IColumn[] columns = Columns; //clone and boxing
for (int i = 0; i < columns.Length; i++)
has |= columns[i].HasChanges;
return has;
}
}
public void AcceptChanges()
{
IColumn[] columns = Columns; //clone and boxing
for (int i = 0; i < columns.Length; i++)
columns[i].AcceptChanges(); //Here we are changing clone
}
}
As you can see from comments we have few problems here with struct cloning. Simple solution to this is to change Column to class, but from my tests it seems that it increases memory usage by ~40% (because of each object metadata) which is not acceptable for me.
So my question is: does anyone have any other ideas how to create methods that can work on different structured objects/records? Maybe someone from F# community can suggest how such problems are solved in functional languages and how it impacts performance and memory usage.
Edit:
sfg thanks for suggestion about macros.
In Visual Studio 2008 there is built-in (but not so known) template engine called T4. Tha whole point is to add '.tt' file to my project and create a template that will search all my classes, recognize somehow the ones that are records (for example by some interface they implement) and produce partial classes with HasChanges and AcceptChanges() that will call only Columns the class contain.
Some usefull links:
T4 Editor for VS
Blog with links and tutorials about T4
Blog entry with example that uses EnvDTE to read project files