gpt4 book ai didi

c# - Duck Typing DynamicObject 派生

转载 作者:行者123 更新时间:2023-11-30 21:20:19 25 4
gpt4 key购买 nike

我写了一个类,它允许派生类指定它的哪些属性可以延迟加载。代码是:

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 或一个 InvalidCastException 并将 SelfHydratingEntity 显式转换回 T。

我知道您可以重写 DynamicObject.TryConvert 方法,但我想知道到底要在这个方法中放入什么。我今天读了很多关于鸭子类型(duck typing)的文章,并尝试了几个库,但没有一个适用于这种特定情况。我今天尝试过的所有库都使用 Reflection.Emit 生成了一个包装器类,它调用“get_”和“set_”方法并自然地使用反射在包装的实例上找到这些方法。 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);

最佳答案

你看到这个了吗Duck Typing项目。看起来不错。我刚找到一个 great example来自 Mauricio .它使用温莎城堡动态代理拦截方法调用

使用 Mauricio 的代码,下面的代码就像做梦一样工作

class Program
{
static void Main(string[] args)
{
dynamic person = new { Name = "Peter" };
var p = DuckType.As<IPerson>(person);

Console.WriteLine(p.Name);
}
}

public interface IPerson
{
string Name { get; set; }
}

public static class DuckType
{
private static readonly ProxyGenerator generator = new ProxyGenerator();

public static T As<T>(object o)
{
return generator.CreateInterfaceProxyWithoutTarget<T>(new DuckTypingInterceptor(o));
}
}

public class DuckTypingInterceptor : IInterceptor
{
private readonly object target;

public DuckTypingInterceptor(object target)
{
this.target = target;
}

public void Intercept(IInvocation invocation)
{
var methods = target.GetType().GetMethods()
.Where(m => m.Name == invocation.Method.Name)
.Where(m => m.GetParameters().Length == invocation.Arguments.Length)
.ToList();
if (methods.Count > 1)
throw new ApplicationException(string.Format("Ambiguous method match for '{0}'", invocation.Method.Name));
if (methods.Count == 0)
throw new ApplicationException(string.Format("No method '{0}' found", invocation.Method.Name));
var method = methods[0];
if (invocation.GenericArguments != null && invocation.GenericArguments.Length > 0)
method = method.MakeGenericMethod(invocation.GenericArguments);
invocation.ReturnValue = method.Invoke(target, invocation.Arguments);
}
}

关于c# - Duck Typing DynamicObject 派生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3349103/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com