私は、派生物が遅延ロードできるプロパティを指定できるようにするクラスを作成しました。コードは次のとおりです。
public abstract class SelfHydratingEntity<T> : DynamicObject where T : class {
private readonly Dictionary<string, LoadableBackingField> fields;
public SelfHydratingEntity(T original) {
this.Original = original;
this.fields = this.GetBackingFields().ToDictionary(f => f.Name);
}
public T Original { get; private set; }
protected virtual IEnumerable<LoadableBackingField> GetBackingFields() {
yield break;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
LoadableBackingField field;
if (this.fields.TryGetValue(binder.Name, out field)) {
result = field.GetValue();
return true;
} else {
var getter = PropertyAccessor.GetGetter(this.Original.GetType(), binder.Name);
result = getter(this.Original);
return true;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
LoadableBackingField field;
if (this.fields.TryGetValue(binder.Name, out field)) {
field.SetValue(value);
return true;
} else {
var setter = PropertyAccessor.GetSetter(this.Original.GetType(), binder.Name);
setter(this.Original, value);
return true;
}
}
}
そして派生クラス:
public class SelfHydratingPerson : SelfHydratingEntity<IPerson> {
private readonly IDataRepository dataRepository;
public SelfHydratingDerivate(IDataRepository dataRepository, IPerson person)
: base(person) {
this.dataRepository = dataRepository
}
protected override IEnumerable<LoadableBackingField> GetBackingFields() {
yield return new LoadableBackingField("Address", () => this.dataRepository.Addresses.Get(this.Original.AddressID));
}
}
これは、プロパティ値の取得と設定には問題なく機能しますが、暗黙的にキャストすると RuntimeBinderException が発生するか、SelfHydratingEntity を T に明示的にキャストして InvalidCastException が発生します。
DynamicObject.TryConvert メソッドをオーバーライドできることはわかっていますが、このメソッドに正確に何を入れればよいのか疑問に思っています。今日、ダック タイピングについて多くのことを読み、いくつかのライブラリを試しましたが、この特定のシナリオでは機能するライブラリはありません。私が今日試したすべてのライブラリは、「get_」および「set_」メソッドを呼び出す Reflection.Emit を使用してラッパー クラスを生成し、自然にリフレクションを使用して、ラップされたインスタンスでこれらのメソッドを見つけます。もちろん、SelfHydratingEntity には "get_" および "set_" メソッドが定義されていません。
だから、このようなことが可能かどうか疑問に思っています。SelfHydratingEntity のインスタンスを T にキャストする方法はありますか? 私はこのようなものを探しています:
var original = GetOriginalPerson();
dynamic person = new SelfHydratingPerson(new DataRepository(), original);
string name = person.Name; // Gets property value on original
var address = person.Address; // Gets property value using LoadableBackingField registration
var iPerson = (IPerson)person;
- or -
var iPerson = DuckType.As<IPerson>(person);