我目前在.NET 2.0应用程序中托管Ironpython。

我想创建一个类(在C#)的类,其实例可以通过插件实例“扩展”。这意味着,在我的实例上无法解决的每个成员访问应转发给适当的插件实例,以提供该成员。然后,我的对象将使用这些插件实例容纳一个私人容器。

AFAIC,去那里的方式是通过dynamicobject派生而来的。到目前为止,第一步很容易,只要Python代码使用我实例的“未知”成员,就会称呼TrygetMember。我还可以返回可以从Python代码中使用的对象和委托。

但是,不知何故,当尝试使用DLR在插件实例和e上执行“ subsearch”时,我被卡住了。 G. Ironpython期望的方式返回插件实例的方法或属性。

欢迎任何提示!

谢谢!

编辑:对不起,我最初的问题还不够清楚。这里有一些要点:

  • 该解决方案必须使用普通的.NET 2.0,no .NET 3.5或4.0允许运行。
  • 插件列表为每个实例(这意味着每个实例可以具有不同的 - 但不可变的 - 插件对象列表)。
  • 插件对象应为所有公共成员(或至少方法和属性)映射的普通c#对象。
  • 碰撞检测并不重要。

再次感谢。

有帮助吗?

解决方案

听起来您想做的是将插件实例输入到对象或动态(与将它们键入某个接口,在该接口中有效地通过TryGetMember请求),然后对另一个对象执行动态绑定。幸运的是,DLR Interop协议允许这种情况!它需要下降到iDynamicMetaObjectProvider层,而不是使用DynamicObject,但实际上很简单。我将向您展示一个简单的示例,使用InvokeMember,该InvokeMember起作用端到端w/ c#4.0。您需要去做其余的操作 - 特别是Ironpython将使用GetMember而不是InvokeMember。但这是一个直接的过程。

首先解释您如何做。在IDMOP级别,DLR处理元对象和语言请求从元对象请求操作,而这些元对象返回更多的元对象。您还可以要求该语言执行其默认绑定,最重要的是,您可以向其提供建议,以建议在出现问题时该怎么做。

基于此,您可以要求语言尝试绑定到每个插件和自己的对象。根据您是否希望插件具有优先插件或动态对象,您可以在最后执行对自己的绑定。该样本根据成员名称演示了这两种技术。

因此,不进一步延迟,这里是:

using System;
using System.Dynamic;
using System.Linq.Expressions;

namespace ConsoleApplication10 {
    class Program {
        static void Main(string[] args) {
            dynamic dynamicObj = new MyDynamicObject(new TestPlugin());
            dynamicObj.Foo();
            dynamicObj.Bar();
            Console.ReadLine();
        }

    }

    public class TestPlugin {
        public void Foo() {
            Console.WriteLine("TestPlugin Foo");
        }

        public void Bar() {
            Console.WriteLine("TestPlugin Bar");
        }
    }

    class MyDynamicObject : IDynamicMetaObjectProvider {
        internal readonly object[] _plugins;

        public void Foo() {
            Console.WriteLine("MyDynamicObject Foo");
        }

        public void Bar() {
            Console.WriteLine("MyDynamicObject Bar");
        }

        public MyDynamicObject(params object[] plugins) {
            _plugins = plugins;
        }

        class Meta : DynamicMetaObject {
            public Meta(Expression parameter, BindingRestrictions restrictions, MyDynamicObject self)
                : base(parameter, restrictions, self) {
            }

            public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) {                
                // get the default binding the language would return if we weren't involved
                // This will either access a property on MyDynamicObject or it will report
                // an error in a language appropriate manner.
                DynamicMetaObject errorSuggestion = binder.FallbackInvokeMember(this, args);

                // run through the plugins and replace our current rule.  Running through
                // the list forward means the last plugin has the highest precedence because
                // it may throw away the previous rules if it succeeds.
                for (int i = 0; i < Value._plugins.Length; i++) {
                    var pluginDo = DynamicMetaObject.Create(Value._plugins[i],
                        Expression.Call(
                            typeof(MyDynamicObjectOps).GetMethod("GetPlugin"),
                            Expression,
                            Expression.Constant(i)
                        )
                    );

                    errorSuggestion = binder.FallbackInvokeMember(pluginDo, args, errorSuggestion);                    
                }

                // Do we want DynamicMetaObject to have precedence?  If so then we can do
                // one more bind passing what we've produced so far as the rule.  Or if the
                // plugins have precedence we could just return the value.  We'll do that
                // here based upon the member name.

                if (binder.Name == "Foo") {
                    return binder.FallbackInvokeMember(this, args, errorSuggestion);
                }

                return errorSuggestion;
            }

            public new MyDynamicObject Value {
                get {
                    return (MyDynamicObject)base.Value;
                }
            }
        }



        #region IDynamicMetaObjectProvider Members

        public DynamicMetaObject GetMetaObject(System.Linq.Expressions.Expression parameter) {
            return new Meta(parameter, BindingRestrictions.Empty, this);
        }

        #endregion
    }

    public static class MyDynamicObjectOps {
        public static object GetPlugin(object myDo, int index) {
            return ((MyDynamicObject)myDo)._plugins[index];
        }
    }
}

运行此印刷品:

mydynamicObject foo testplugin bar

表明对于FOO成员,我们更喜欢对实际对象的绑定,而对于酒吧成员,我们更喜欢bar。如果添加了对第三个BAZ成员的访问,则会产生C#的运行时活页夹异常。如果这是从Ironpython调用的,我们将生成Python程序(.NET中缺少的Memberexception)的属性,并且JavaScript Imellions应该返回未定义的程序。

因此,您不仅可以获得可扩展的插件系统,还可以轻松地在任何消耗对象的langauge中获得正确的行为。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top