Domanda

Sono attualmente ospita IronPython in un'applicazione .NET 2.0.

Voglio creare una classe (in C #) le cui istanze possono essere "estesa" di plug istanze. Ciò significa che, ogni accesso utente che è irrisolvibile sulla mia istanza deve essere trasmessa l'istanza di plug-in appropriato a condizione che membro. Il mio oggetto terrà un contenitore privato con quelle istanze di plugin poi.

AFAICS, la strada da percorrere non v'è via derivanti da DynamicObject. Il primo passo è stato facile finora che TryGetMember viene chiamato ogni volta utilizza il codice python "sconosciute" membri della mia istanza. Ho anche potuto restituire gli oggetti ei delegati che potrebbero essere utilizzati dal codice python.

Ma, in qualche modo, mi sono bloccato quando si cerca di utilizzare il DLR per eseguire la "SubSearch" per l'istanza del plugin e e. G. restituire un metodo o una proprietà dell'istanza plug-in nel modo IronPython si aspetta.

Eventuali suggerimenti sono i benvenuti!

Grazie!

Edit: La mia domanda iniziale non è stata formulata abbastanza chiaro, mi spiace. Ecco alcuni punti:

  • La soluzione deve funzionare con normale .NET 2.0, nessun NET 3.5 o 4.0 ammessi.
  • La lista dei plug-in sono per esempio (che significa ogni istanza può avere un diverso - ma immutabili - elenco di oggetti plugin)
  • .
  • Gli oggetti plugin dovrebbe essere oggetti semplici C # con tutti i membri pubblici (o almeno metodi e proprietà) mappate.
  • Il rilevamento delle collisioni non è importante.

Grazie ancora.

È stato utile?

Soluzione

Che suona come si vuole fare è avere le istanze di plugin digitato per oggetto o dinamica (rispetto averli digitati in una certa interfaccia in cui si passa in modo efficace attraverso la richiesta TryGetMember) e quindi eseguire una dinamica vincolante contro un altro oggetto. Fortunatamente per voi DLR interoperabilità protocollo consente esattamente questo scenario! Sarà richiede di discesa allo strato IDynamicMetaObjectProvider invece di utilizzare DynamicObject ma in realtà è abbastanza semplice. Vi mostrerò un semplice esempio utilizzando InvokeMember che funziona end-to-end w / C # 4.0. Avrai bisogno di andare a fare il resto delle operazioni - in particolare IronPython utilizzerà GetMember invece di InvokeMember. Ma questo è un processo dritto in avanti.

Per prima cosa una spiegazione di come lo si fa. A livello IDMOP le offerte DLR con oggetti meta e linguaggi richiedere operazioni da oggetti meta e quegli oggetti meta restituire gli oggetti più meta. Si può anche chiedere la lingua per eseguire legandolo del difetto e, soprattutto, è possibile fornire ad essa un suggerimento di cosa fare quando le cose vanno male.

Sulla base di che si può chiedere il linguaggio per cercare e si legano a ciascuno dei tuoi plugin e il proprio oggetto. A seconda se si desidera che i plugin di avere la precedenza, o il vostro oggetto dinamico, è possibile eseguire il binding a se stessi scorso. Questo esempio illustra entrambe le tecniche basate sui nomi dei membri.

Quindi, senza ulteriori indugi, ecco che è:

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

Esecuzione Questo stampa:

MyDynamicObject Foo TestPlugin Bar

Mostra che per i membri Foo noi preferiamo la vincolante per l'oggetto reale, e per i bar preferiamo Bar. Se si aggiunge l'accesso a un terzo membro Baz produce runtime eccezione C # s 'legante. Se questo è stato chiamato da IronPython avremmo produrre un AttributeError ai programmi Python (un MissingMemberException in NET) e realizzare un JavaScript dovrebbe return undefined ai loro programmi.

Così si ottiene non solo il sistema di plugin estendibile anche facilmente ottenere il comportamento corretto in qualsiasi langauge che consuma l'oggetto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top