Делегирование динамического разрешения объекта в другие случаи

StackOverflow https://stackoverflow.com/questions/4758678

Вопрос

В настоящее время я принимаю Ironpython в приложении .NET 2.0.

Я хочу создать класс (в C#), экземпляры которых могут быть «расширены» по экземплярам плагина. Это означает, что доступ к каждому участнику, который неразрешимый в моем экземпляре, должен быть направлен в соответствующий экземпляр плагина, предоставляя этот член. Мой объект будет держать частный контейнер с этими экземплярами плагина.

Афаики, путь туда проходит через DynamicObject. Первый шаг был простым, когда TrygetMember вызывается всякий раз, когда Python Code использует «неизвестные» членов моего экземпляра. Я также мог бы вернуть объекты и делегаты, которые можно использовать из кода Python.

Но каким -то образом я застрял, пытаясь использовать DLR для выполнения «добычи» в экземпляре плагина и e. G. вернуть метод или свойство экземпляра плагина так, как это ожидает Ironpython.

Любые подсказки приветствуются!

Спасибо!

РЕДАКТИРОВАТЬ: Мой первоначальный вопрос не был сформулирован достаточно ясным, извините. Вот несколько моментов:

  • Решение должно работать с простым .NET 2.0, NO .NET 3.5 или 4.0.
  • Список плагина - это экземпляры (что означает, что каждый экземпляр может иметь другой - но неизбежный - список объектов плагина).
  • Объекты плагина должны быть простыми объектами C# со всеми общедоступными членами (или, по крайней мере, методами и свойствами).
  • Обнаружение столкновения не важно.

Спасибо еще раз.

Это было полезно?

Решение

Похоже, что вы хотите сделать, это набрать экземпляры плагинов в объект или динамический (в отличие от их набора их на какой -то интерфейс, где вы эффективно проходите через запрос TrygetMember), а затем выполняете динамическое привязку с другим объектом. К счастью для вас, протокол Interop DLR допускает именно этот сценарий! Требуется опуститься на слой IdyNamicMetaObjectProvider вместо использования DynamicObject, но на самом деле это довольно просто. Я покажу вам простой пример, используя Invokemember, который работает в конце концов W/ C# 4.0. Вам нужно будет пойти и выполнить оставшуюся часть операций - в частности, Ironpython будет использовать getmember вместо Invokemempeme. Но это простой процесс.

Сначала объяснение того, как вы это делаете. На уровне IDMOP DLR имеет дело с операциями Meta -объектов и языков за запросами от Meta -объектов, и эти Meta -объекты возвращают больше мета -объектов. Вы также можете попросить язык выполнить его обязательство по умолчанию, и самое главное, вы можете дать ему предложение о том, что делать, когда дела идут не так.

Исходя из этого, вы можете попросить язык попытаться привязать к каждому из ваших плагинов и вашего собственного объекта. В зависимости от того, хотите ли вы, чтобы плагины имели приоритет или ваш динамический объект, вы можете выполнить привязку к себе последним. Этот образец демонстрирует оба метода на основе имен участников.

Итак, без дальнейшей задержки, вот оно:

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 мы предпочитаем привязку к фактическому объекту, и для членов бара мы предпочитаем бар. Если вы добавите доступ к третьему участнику BAZ, он создает исключение переплетения C#. Если бы это было вызвано из Ironpython, мы создали бы атрибут программ Python (пропущенное memberexception в .net), а реализация JavaScript должно вернуть не определенные в свои программы.

Таким образом, вы получаете не только свою расширяемую систему плагина, вы также легко получаете правильное поведение в любом Langauge, который потребляет ваш объект.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top