Question

J'accueille actuellement IronPython dans une application .NET 2.0.

Je veux créer une classe (en C #) dont les instances peuvent être « étendu » par des instances plugin. Cela signifie que, chaque accès membre qui est mon cas sans solution doit être transmis à l'instance de plugin approprié à condition que membre. Mon objet organisera un conteneur privé avec les instances de plug-ins alors.

AFAICS, la façon de s'y rendre est par dérivation de DynamicObject. La première étape a été facile jusqu'à présent que TryGetMember est appelée chaque fois que le code python usages membres « inconnus » de mon exemple. Je pourrais aussi retourner des objets et des délégués qui pourraient être utilisés à partir du code python.

Mais, en quelque sorte, je suis resté bloqué en essayant d'utiliser le DLR pour effectuer la « recherche complémentaire » sur l'instance de plug-in et e. G. renvoyer une méthode ou une propriété de l'instance du plug-in de la manière IronPython attend.

Les conseils sont les bienvenus!

Merci!

Edit: Ma première question n'a pas été formulée assez clair, désolé. Voici quelques points:

  • La solution doit fonctionner avec .NET 2.0 ordinaire, pas .NET 3.5 ou 4.0 autorisé.
  • La liste des plug-in sont par exemple (ce qui signifie chaque instance peut avoir un autre - mais immuable - liste des objets plugin)
  • .
  • Les objets de plug-ins doivent être des objets simples C # avec tous les membres du public (ou au moins les méthodes et propriétés) mis en correspondance.
  • Détection de collision n'a pas d'importance.

Merci encore.

Était-ce utile?

La solution

Qu'est-ce que il semble que vous voulez faire est d'avoir vos instances de plug-in tapé à l'objet ou dynamique (contre eux ayant tapés à une interface où vous passez efficacement par la demande TryGetMember), puis effectuez une liaison dynamique contre un autre objet. Heureusement pour vous le DLR Interop protocole permet exactement ce scénario! Il va me falloir de descendre à la couche IDynamicMetaObjectProvider au lieu d'utiliser DynamicObject mais il est en fait assez simple. Je vais vous montrer un exemple simple en utilisant InvokeMember qui fonctionne de bout en bout avec / C # 4.0. Vous aurez besoin d'aller faire le reste des opérations - en particulier IronPython utilisera GetMember au lieu de InvokeMember. Mais c'est un processus simple.

D'abord une explication de la façon dont vous le faites. Au niveau de IDMOP les offres de DLR avec des objets méta et langues demandent des opérations à partir d'objets méta et les objets méta renvoient des objets plus meta. Vous pouvez également demander à la langue de l'exécuter de liaison par défaut et plus important encore, vous pouvez fournir une suggestion de ce qu'il faut faire quand les choses tournent mal.

Sur la base que vous pouvez demander à la langue pour essayer de se lier à chacun de vos plugins et votre propre objet. Selon que vous voulez plugins d'avoir la priorité, ou votre objet dynamique, vous pouvez effectuer la liaison à vous-même dernier. Cet exemple illustre les techniques basées sur les noms de membres.

Alors sans plus tarder, voici:

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

L'exécution de cette impression:

MonObjetDynamique Foo Bar TestPlugin

Montrer que pour les membres Foo nous préférons la liaison sur l'objet réel, et pour les membres, nous préférons Bar Bar. Si vous ajoutez l'accès à un troisième élément Baz, il produit exception de liant d'exécution de C #. Si cela a été appelé à partir IronPython que nous avions produire un AttributeError aux programmes Python (un MissingMemberException dans .NET) et JavaScript en œuvre devrait revenir undefined à leurs programmes.

Ainsi, vous obtenez non seulement votre système de plugin extensible vous aussi facilement obtenir le comportement correct dans toute langauge qui consomme votre objet.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top