私はジェネリックを試していて、Dataset クラスに似た構造を作成しようとしています。
次のコードがあります
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();
}
}
問題は、新しい列を追加するときに、HasChanges プロパティと AcceptChanges() メソッドにも追加する必要があることです。これは、いくつかのリファクタリングを要求するだけです。
だから私の頭に浮かんだ最初の解決策は次のようなものでした:
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
}
}
コメントからわかるように、ここでは構造体の複製に関する問題はほとんどありません。これに対する簡単な解決策は、Column をクラスに変更することですが、私のテストでは、(各オブジェクトのメタデータのために) メモリ使用量が ~40% 増加するようで、これは私には受け入れられません。
私の質問は次のとおりです。さまざまな構造化オブジェクト/レコードで機能するメソッドを作成する方法を他に考えている人はいますか? F# コミュニティの誰かが、このような問題が関数型言語でどのように解決され、パフォーマンスとメモリ使用量にどのように影響するかを提案できるかもしれません。
編集:
sfg マクロに関する提案に感謝します。
Visual Studio 2008 には、T4 と呼ばれる組み込みの (しかしあまり知られていない) テンプレート エンジンがあります。全体のポイントは、「.tt」ファイルをプロジェクトに追加し、すべてのクラスを検索するテンプレートを作成し、レコードであるクラスを何らかの方法で認識し (たとえば、実装するインターフェイスによって)、HasChanges および AcceptChanges( ) クラスに含まれる列のみを呼び出します。
いくつかの便利なリンク:
VS ブログの T4 エディター ( EnvDTE を使用してプロジェクト ファイルを読み取る例を含む
T4 ブログ エントリに関するリンクとチュートリアルを含む)