Есть ли эквивалент InterfaceMapping для свойств и событий? - PullRequest
3 голосов
/ 19 ноября 2010

Я строю генератор Mixin.Я хотел бы знать, когда мне нужно избегать создания свойства для искажений, чтобы публичный API точно совпадал.Это важно для использования с Dynamic, так как в противном случае существует несколько свойств с одним и тем же именем (если я просто пойду и добавлю свойства одно за другим), средство связывания типа времени выполнения просто выберет первое, которое может бытьтот, который я хочу.

Для методов я могу использовать InterfaceMapping и словарь, чтобы не писать несколько методов пересылки для одного и того же метода.(Я просто говорю, что этот метод переопределяется тем же методом).

Таким образом, если, например, я смешиваю Dictionary<String,String>, который реализует как IDictionary<string,string>, так и обычный IDictionary, мне нужно только открытое свойство String Item[String], а не Object Item[Object].

То же самое для EventHandlers, хотя я не думаю, что это большая проблема.

Прямо сейчас мой API создает свойство, только если базовое свойство или событие имеют новые методы, но когда я все еще смотрю на свой словарь, смешанный с объектом, у него все еще есть дублированные члены.

Вотсоответствующие фрагменты кода, весь класс довольно большой (и даже эти методы немного больше, чем мне нравится :() Драйвер добавляет все не специальные методы имен, найденные в карте интерфейса, затем проходит через каждое свойство и событие на картеи вызывает CreateMixinForwardingProperty/Event. Я думаю, мне нужно отфильтровать те, которые реализованы явно в миксине, но как?

    private static void CreateMixinForwardingEvent(TypeBuilder typeBuilder, FieldBuilder mixInField, EventInfo eventInfo, InterfaceMapping interfaceMap, Dictionary<MethodInfo, MethodBuilder> methodMap)
    {
        var indexOfAdd = Array.IndexOf(interfaceMap.InterfaceMethods, eventInfo.GetAddMethod());
        bool createdNew;
        var addMethodBuilder = CreateOrGetMixinForwardingMethod(
            typeBuilder, 
            mixInField, 
            interfaceMap.InterfaceMethods[indexOfAdd],
            interfaceMap.TargetMethods[indexOfAdd],
            methodMap,
            out createdNew
        );
        if (createdNew)
        {
            var eventBuilder = typeBuilder.DefineEvent(eventInfo.Name, eventInfo.Attributes, eventInfo.EventHandlerType);
            eventBuilder.SetAddOnMethod(addMethodBuilder);
            var indexOfRemove = Array.IndexOf(interfaceMap.InterfaceMethods, eventInfo.GetRemoveMethod());
            eventBuilder.SetRemoveOnMethod(
                CreateOrGetMixinForwardingMethod(
                    typeBuilder,
                    mixInField,
                    interfaceMap.InterfaceMethods[indexOfRemove],
                    interfaceMap.TargetMethods[indexOfRemove],
                    methodMap,
                    out createdNew
                )
            );
        }
    }

    private static void CreateMixinForwardingProperty(TypeBuilder typeBuilder, FieldBuilder mixInField, PropertyInfo propertyInfo, InterfaceMapping interfaceMap, Dictionary<MethodInfo, MethodBuilder> methodMap)
    {
        PropertyBuilder propertyBuilder = null;// = typeBuilder.DefineProperty(propertyInfo.Name, propertyInfo.Attributes, propertyInfo.PropertyType,propertyInfo.GetIndexParameters().Select(p=>p.ParameterType).ToArray());
        MethodBuilder propertyGetMethod = null;
        MethodBuilder propertySetMethod;
        bool createdNew;
        if (propertyInfo.CanRead)
        {
            var indexOfGet = Array.IndexOf(interfaceMap.InterfaceMethods, propertyInfo.GetGetMethod());
            propertyGetMethod = CreateOrGetMixinForwardingMethod(
                    typeBuilder,
                    mixInField,
                    interfaceMap.InterfaceMethods[indexOfGet],
                    interfaceMap.TargetMethods[indexOfGet],
                    methodMap,
                    out createdNew
                );
            if (createdNew)
            {
                propertyBuilder = typeBuilder.DefineProperty(propertyInfo.Name, propertyInfo.Attributes, propertyInfo.PropertyType, propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray());
                propertyBuilder.SetGetMethod(propertyGetMethod);
            }
        }
        if (propertyInfo.CanWrite)
        {
            var indexOfSet = Array.IndexOf(interfaceMap.InterfaceMethods, propertyInfo.GetSetMethod());
            propertySetMethod = CreateOrGetMixinForwardingMethod(
                typeBuilder,
                mixInField,
                interfaceMap.InterfaceMethods[indexOfSet],
                interfaceMap.TargetMethods[indexOfSet],
                methodMap,
                out createdNew
            );
            if (createdNew)
            {
                if (propertyBuilder == null)
                {
                    propertyBuilder = typeBuilder.DefineProperty(propertyInfo.Name, propertyInfo.Attributes, propertyInfo.PropertyType, propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray());
                    if (propertyInfo.CanRead) propertyBuilder.SetGetMethod(propertyGetMethod);
                }
                propertyBuilder.SetSetMethod(propertySetMethod);
            }
        }
    }


    private static MethodBuilder CreateOrGetMixinForwardingMethod(TypeBuilder typeBuilder, FieldBuilder mixinField, MethodInfo interfaceMethod, MethodInfo mixinMethod, Dictionary<MethodInfo, MethodBuilder> methodMap,out bool createdNew)
    {
        MethodBuilder overrideMethod;
        if (createdNew = !methodMap.TryGetValue(mixinMethod, out overrideMethod))
        {
            overrideMethod = typeBuilder.DefineMethod(mixinMethod.Name, mixinMethod.Attributes, CallingConventions.HasThis, interfaceMethod.ReturnType, interfaceMethod.GetParameters().Select(p => p.ParameterType).ToArray());
            var ilgen = overrideMethod.GetILGenerator();
            LoadParameters(ilgen, 1);
            ilgen.Emit(OpCodes.Ldfld, mixinField);
            LoadParameters(ilgen, interfaceMethod.GetParameters().Length, 1);
            ilgen.Emit(OpCodes.Callvirt, interfaceMethod);
            ilgen.Emit(OpCodes.Ret);
            methodMap.Add(mixinMethod, overrideMethod);
        }
        typeBuilder.DefineMethodOverride(overrideMethod, interfaceMethod);
        return overrideMethod;
    }

Я знаю, что мне не нужно реализовывать свойства или события, которые реализованы только явнокак при приведении к типу интерфейса, они будут работать правильно, а динамический просмотр только общедоступных членов.

edit: Поскольку я удалил комментарии, чтобы немного упростить вставку, генератор добавляет поле длясмешанный в элементе для переопределения базового типа, и для каждого метода, который яmplements просто загружает поле mixin и вызывает метод со свойством mixin.Я называю этот процесс пересылкой сообщений, отсюда и название.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...