5

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は「動的テスト = new Test(); 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; }
}

これはバルトスのおかげです。

しかし、それは基本的にマークが提供したもののようです。

良い出発点を教えてください!他の提案がある場合は、これを今のところ開いたままにします。

この質問の結果、

実際のプロジェクトではなく、ただのプロトタイピングですが、私たちが望んでいたものを達成しました。

4

2 に答える 2

3

評価の各ステップは個別です。それは評価しません.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;
        }
    }
}
于 2012-09-28T06:05:22.777 に答える
1

おそらく、'DynamicObject' の代わりに基本的な動的インターフェースを実装することで、このようにすることもできますが、最も簡単な方法は、'Posts' の動的呼び出しで、'Load' メソッドを処理する別の DynamicObject を返すことです。

于 2012-09-28T05:59:57.823 に答える