【问题标题】:Possible to get chained value of DynamicObject?可以获得 DynamicObject 的链式值吗?
【发布时间】:2012-09-28 05:47:02
【问题描述】:

创建一个实现 DynamicObject 的类

public class Test : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (binder.Name == ("Posts"))
        {
            result = "property accessed was 'Posts'";
            return true;   
        }

        return base.TryGetMember(binder, out result);
    }
}

我可以打电话

dynamic test = new Test();
var result = test.Posts;

result的值为“动态测试=新测试(); var 结果 = test.Posts;"

没关系。

我想知道的是,当 TryGetMember 被调用时,是否有可能获得链式值。

所以如果我打电话:

dynamic test = new Test();
var result = test.Posts.Load(123);

然后我可以这样做:

if (binder.Name == ("Posts"))
{
    if (... == "Load")
        result = this.Load<Post>(... 123);
    return true;   
}

这样的事情可能吗?我想不出办法。

到目前为止我有:

class Program
{
    static void Main(string[] args)
    {
        dynamic test = new Test();
        dynamic result = test.Posts.Load(123);

        Console.WriteLine(result.Name);

        dynamic result2 = test.Posts.Load(909);

        Console.WriteLine(result2.Name);

        Console.ReadKey();
    }
}

public class Test : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (binder.Name == ("Posts"))
        {
            result = new ChainBuilder(this, "Post");
            return true;   
        }

        return base.TryGetMember(binder, out result);
    }

    public T Load<T>(int id) where T : Post, new()
    {
        if (id == 123)
            return new T {Id = 123, Name = "Bananas"};

        return new T {Id = 0, Name = "Others"};
    }

    private class ChainBuilder : DynamicObject
    {
        public dynamic OriginalObject { get; set; }
        public string PropertyInvoked { get; set; }

        public ChainBuilder(DynamicObject originalObject, string propertyInvoked)
        {
            OriginalObject = originalObject;
            PropertyInvoked = propertyInvoked;
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            if (binder.Name == "Load")
            {
                result = OriginalObject.Load<Post>((int)args[0]);
                return true;
            }

            return base.TryInvokeMember(binder, args, out result);
        }
    }
}

public class Post
{
    public int Id { get; set; }
    public string Name { get; set; }
}

这要感谢 Bartosz。

但看起来这基本上是 Marc 提供的。

给我一​​个好的起点!如果有任何其他建议,我将暂时保留此功能。

这个问题导致

不是真正的项目,只是原型设计,但实现了我们想要的。

【问题讨论】:

    标签: c# dynamic


    【解决方案1】:

    评估的每一步都是独立的;它不评估.Posts.Load(123) - 它评估.Posts,然后分别评估.Load(123),所以不:你不能一步完成。诀窍是自己组合值,例如:

    using System;
    using System.Dynamic;
    using System.Text;
    static class Program {
        static void Main() {
            dynamic test = new Test();
            var result = test.Posts.Foo.Bar(123, "abc");
            Console.WriteLine(result);
        }
    }
    public class Test : DynamicObject
    {
        public override bool TryGetMember(GetMemberBinder binder,
            out object result)
        {
            result = new MemberAccessWrapper("member accessed was " + binder.Name);
            return true;
        }
        private class MemberAccessWrapper : DynamicObject
        {
            private readonly string message;
            public override bool TryInvoke(InvokeBinder binder, object[] args,
                out object result)
            {
                StringBuilder builder = new StringBuilder(message).Append("(");
                for(int i = 0 ; i < args.Length ; i++) {
                    if(i!=0)builder.Append(", ");
                    if (args[i] == null) {
                        builder.Append("null");
                    } else if (args[i] is string) {
                        builder.Append("@\"").Append(((string)args[i])
                             .Replace("\"", "\"\"")).Append("\"");
                    } else {
                        builder.Append(args[i]);
                    }
                }
                builder.Append(")");
                result = new MemberAccessWrapper(builder.ToString());
                return true;
            }
            public MemberAccessWrapper(string message)
            {
                this.message = message;
            }
            public override string ToString()
            {
                return message;
            }
            public override bool TryGetMember(GetMemberBinder binder,
                out object result)
            {
                result = new MemberAccessWrapper(message + "." + binder.Name);
                return true;
            }
        }
    }
    

    【讨论】:

    • 太棒了,我只是在编辑我的帖子,而你发布了你的帖子。谢谢!
    【解决方案2】:

    也许您可以通过实现基本动态接口而不是“DynamicObject”来做到这一点,但最简单的方法是让您动态调用“Posts”只返回另一个处理“Load”方法的DynamicObject。

    【讨论】:

      猜你喜欢
      • 2011-03-24
      • 1970-01-01
      • 1970-01-01
      • 2011-07-28
      • 1970-01-01
      • 1970-01-01
      • 2021-04-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多