Frage

Ich habe derzeit Ironpython in einer .NET 2.0 -Anwendung veranstaltet.

Ich möchte eine Klasse (in C#) erstellen, deren Instanzen von Plugin -Instanzen "erweitert" werden können. Das bedeutet, dass jedes Mitgliedszugriff, das in meiner Instanz nicht löslich ist, an die entsprechende Plugin -Instanz weitergeleitet werden sollte, die dieses Mitglied bereitstellt. Mein Objekt enthält dann einen privaten Container mit diesen Plugin -Instanzen.

AFAICS, der Weg dorthin, indem er von DynamicObject abgeleitet wird. Der erste Schritt war bisher einfach, dass TrygetMember aufgerufen wird, wenn Python -Code "unbekannte" Mitglieder meiner Instanz verwendet. Ich könnte auch Objekte und Delegierte zurückgeben, die aus dem Python -Code verwendet werden könnten.

Aber irgendwie bin ich stecken geblieben, als ich versuchte, die DLR zu verwenden, um die "SubSearch" in der Plugin -Instanz und e durchzuführen. G. Gibt eine Methode oder Eigenschaft der Plugin -Instanz in der Art und Weise, wie Ironpython erwartet, zurück.

Alle Hinweise sind willkommen!

Vielen Dank!

Bearbeiten: Meine ursprüngliche Frage wurde nicht klar genug, sorry. Hier einige Punkte:

  • Die Lösung muss mit einfacher .NET 2.0, Nr. Nr. 3.5 oder 4.0 zulässig ausgeführt.
  • Die Plugin -Liste ist pro Instanz (dh jeder Instanz kann eine andere, aber unveränderliche Liste von Plugin -Objekten haben).
  • Die Plugin -Objekte sollten einfache C# -Objekte mit allen öffentlichen Mitgliedern (oder zumindest Methoden und Eigenschaften) sein.
  • Die Kollisionserkennung ist nicht wichtig.

Danke noch einmal.

War es hilfreich?

Lösung

Es klingt so, als ob Sie Ihre Plugin -Instanzen für Objekt oder Dynamik eingeben möchten (anstatt sie an eine Schnittstelle einzugeben, an der Sie die Anforderung von TryGetMember effektiv durchgeben) und dann eine dynamische Bindung gegen ein anderes Objekt durchführen. Zum Glück für Sie ermöglicht das DLR Interop -Protokoll genau dieses Szenario! Es muss auf die idynamicMetaObjectProvider -Schicht fallen gelassen werden, anstatt DynamicObject zu verwenden, aber sie ist eigentlich ziemlich einfach. Ich zeige Ihnen ein einfaches Beispiel mit InvoKemember, das End-to-End mit# 4.0 funktioniert. Sie müssen den Rest der Operationen durchführen - insbesondere Ironpython verwendet GetMember anstatt invoKemember. Aber das ist ein einfacher Prozess.

Zuerst eine Erklärung, wie Sie es machen. Auf der IDMOP -Ebene befasst sich der DLR mit Meta -Objekten und Sprachen an, die Operationen von Meta -Objekten anfordern, und diese Metaobjekte geben mehr Meta -Objekte zurück. Sie können auch die Sprache bitten, ihre Standardbindung durchzuführen, und vor allem können Sie ihr einen Vorschlag dafür geben, was zu tun ist, wenn etwas schief geht.

Basierend darauf können Sie die Sprache bitten, zu versuchen, sich an jedes Ihrer Plugins und Ihr eigenes Objekt zu binden. Abhängig davon, ob Plugins Vorrang oder Ihr dynamisches Objekt haben, können Sie die Bindung an sich selbst zuletzt durchführen. Diese Probe zeigt beide Techniken, die auf den Mitgliedsnamen basieren.

So ist es ohne weitere Verzögerung hier:

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];
        }
    }
}

Ausdruck dieses Drucks:

MydynamicObject Foo Testplugin Bar

Zeigen Sie, dass wir für FOO -Mitglieder die Bindung des tatsächlichen Objekts bevorzugen, und für Barmitglieder bevorzugen wir Bar. Wenn Sie Zugriff auf ein drittes BAZ -Mitglied hinzufügen, erzeugt die Binder -Binder -Ausnahme von C#. Wenn dies von Ironpython genannt wurde, würden wir einen AttributeError für Python -Programme (eine vermisste Memberexception in .NET) erstellen, und ein JavaScript -Implementierung sollte undefiniert zu ihren Programmen zurückkehren.

Sie erhalten also nicht nur Ihr erweiterbares Plugin -System. Sie erhalten auch einfach das richtige Verhalten in jeder Langauge, die Ihr Objekt verbraucht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top