再利用可能性のためのインデックス変換/マッピングに名前を生成してコンパイルする
-
11-12-2019 - |
質問
サービスからデータを取得したとします(コントロールできない)
public class Data
{
// an array of column names
public string[] ColumnNames { get; set; }
// an array of rows that contain arrays of strings as column values
public string[][] Rows { get; get; }
}
.
および中間層上で、これをIEnumerable<Entity>
の列名は、My Data
クラスのプロパティとして表されるがになることができるEntity
にマッピング/変換したいと思います。私はがになるかもしれませんが、サービスによって返されたすべてのデータが必要ではなく、それのほんの一部が必要なので
変換
これは翻訳をするためのアルゴリズムの抽象化です:
-
IDictionary<string, int>
のColumnNames
を作成するので、個々の列名を個々の行の配列インデックスに簡単にマッピングできます。
- Reflectionを使用してMy
Entity
プロパティの名前を調べて、列名と一致することができるように
-
Data.Rows
を繰り返し、Entity
オブジェクトを作成し、#1で行われたマッピングに従ってプロパティを入力します。それらを設定するためにプロパティに反射とSetValue
を使用する可能性があります。
最適化
上位アルゴリズムはもちろん作業であるが、それが反映を使用するのでそれがいくつかのキャッシングをするべきであること、そしておそらくその場である可能性があるので、それはかなりのものをスピードアップすることができると思います。
ステップ1と2が完了したら、実際に文字列の配列をとり、インデックスを直接インデックスを使用してインスタンス化し、をコンパイルし、をキャッシュする方法を将来の再利用のためにインスタンス化することができます。
通常、結果のページを取得するので、後続の要求は同じコンパイル方法を再利用します。
IDictionary<string, int>
のColumnNames
を作成するので、個々の列名を個々の行の配列インデックスに簡単にマッピングできます。
Entity
プロパティの名前を調べて、列名と一致することができるように
Data.Rows
を繰り返し、Entity
オブジェクトを作成し、#1で行われたマッピングに従ってプロパティを入力します。それらを設定するためにプロパティに反射とSetValue
を使用する可能性があります。
最適化
上位アルゴリズムはもちろん作業であるが、それが反映を使用するのでそれがいくつかのキャッシングをするべきであること、そしておそらくその場である可能性があるので、それはかなりのものをスピードアップすることができると思います。
ステップ1と2が完了したら、実際に文字列の配列をとり、インデックスを直接インデックスを使用してインスタンス化し、をコンパイルし、をキャッシュする方法を将来の再利用のためにインスタンス化することができます。
通常、結果のページを取得するので、後続の要求は同じコンパイル方法を再利用します。
追加の事実
これは質問(および回答)に不可欠ではありませんが、これらが名前で一致しない場合の列からプロパティのマッピングに役立つ2つの属性を作成しました。私は最も明白なMapNameAttribute
(文字列を取り、オプションでオプションで任意選択でも有効にし、oppentivityを有効にします)およびIgnoreMappingAttribute
のPropertiesのデータにマッピングされるべきではありません。しかし、これらの属性は上限アルゴリズムの手順2で読み込まれているため、プロパティ名は収集され、この宣言型メタデータに従って列名と一致するように変更されます。
質問
そのような方法を生成してコンパイルするための最善かつ最も簡単な方法は何ですか?ラムダ表現? Entity
クラス?
生成されたコードとコンパイル済みのコードの例が似ていますか。私はマッピングがかなり一般的なシナリオです。
注:その間、私はPetapoco(そしてまた大量)を調べるでしょう(そして、彼らが両方ともマッピング目的のために正確に編集とキャッシングをしているので、Petapoco(多分大量)を調べます。
MapNameAttribute
(文字列を取り、オプションでオプションで任意選択でも有効にし、oppentivityを有効にします)およびIgnoreMappingAttribute
のPropertiesのデータにマッピングされるべきではありません。しかし、これらの属性は上限アルゴリズムの手順2で読み込まれているため、プロパティ名は収集され、この宣言型メタデータに従って列名と一致するように変更されます。
Entity
クラス?
注:その間、私はPetapoco(そしてまた大量)を調べるでしょう(そして、彼らが両方ともマッピング目的のために正確に編集とキャッシングをしているので、Petapoco(多分大量)を調べます。
解決
提案: Nuget からFastMemberを入手する
それからだけ使用してください:
var accessor = TypeAccessor.Create(typeof(Entity));
.
現在の反復のmemberName
とnewValue
を見つけたら、
accessor[obj, memberName] = newValue;
.
これはあなたが尋ねていることをするように設計されています。内部的には、前に見た場合は一連の種類を維持します。新しいタイプが表示されている場合は、TypeAccessor
の新しいサブクラス(TypeBuilder
を介して)作成してキャッシュします。それぞれの固有のTypeAccessor
は、そのタイプのプロパティを認識しており、基本的にはa:のように機能します。
switch(memberName) {
case "Foo": obj.Foo = (int)newValue;
case "Bar": obj.Bar = (string)newValue;
// etc
}
.
これはキャッシュされているので、あなたは初めてあなたのタイプを見たことがあるのは初めての費用(実際には big>コストではありません)のみを支払うだけです。残りの時間は無料です。 ILGenerator
を直接使用するため、例えばExpression
またはCodeDOMを介して不要な抽象化も回避されますので、それができる限り速いです。
(私はdynamic
型の場合、IDynamicMetaObjectProvider
を実装するタイプも明確にする必要があります。
追加:
がを使っていることは次のとおりです。その後、すべてのVoodooがメンバー名ではなく、 data 名で起こります。
これは線を変えることを意味するでしょう:
.
il.Emit(OpCodes.Ldstr, prop.Name);
と
.
il.Emit(OpCodes.Ldstr, field.Name);
FastMember
とMapNameAttribute
の両方で、IgnoreMappingAttribute
ループの開始時にWriteGetter
を実行する場合は、無視される場合は