首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >鸭型DynamicObject衍生体

鸭型DynamicObject衍生体
EN

Stack Overflow用户
提问于 2010-07-28 00:42:08
回答 2查看 1.3K关注 0票数 2

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

代码语言:javascript
复制
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;
        }
    }
}

以及衍生类:

代码语言:javascript
复制
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。

我知道您可以重写DynamicObject.TryConvert方法,但是我想知道在这个方法中到底要放什么。今天我读了很多关于鸭子输入的文章,并且尝试了几个库,但是它们都不适合这个特定的场景。我今天尝试过的所有库都使用Reflection.Emit生成一个包装类,该类调用"get_“和"set_”方法,并自然地使用反射在包装的实例上找到这些方法。当然,SelfHydratingEntity没有定义"get_“和"set_”方法。

所以,我想知道这种事情是否可能发生。是否有任何方法将SelfHydratingEntity的实例转换为T?我在找这样的东西:

代码语言:javascript
复制
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);
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-07-28 00:56:31

你看过这个鸭型项目吗?看起来挺不错的。我刚找到一个来自莫里西奥莫里西奥。它使用温莎城堡动态代理来拦截方法调用。

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

代码语言:javascript
复制
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);
    }
}
票数 2
EN

Stack Overflow用户

发布于 2011-02-28 13:58:44

即席接口https://github.com/ekonbenefits/impromptu-interface

可以将静态接口转换到从DynamicObject派生的对象。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3349103

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档