jakesays-old / runsharp

Automatically exported from code.google.com/p/runsharp
MIT License
1 stars 0 forks source link

Some issues and their solution #24

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
lets say you have a Type (T) that implements an interface (I1) 
T : I1
and I1 is implementing an other interface I2
I1 : I2

1. If your are implementing a Type that implements Interface I1 than runsharp 
is not checking for the proper implementation of the methods of I2 AND does not 
call tb.DefineMethodOverride in any situation which makes it impossible to 
implement them. (You get a TypeLoadException at type completion)

2. If you are using a variable (Operand) with type of I1 you can't use the 
methods of I2

3. You can't create nested Delegates
4. You can't create Explicit Event implementations

I needed all of those features so i added them myself (i added the changed 
files as attachments, they should work with 0.1.2, but maybe i changed other 
things as well!):
Fix for Issue 1+2:
Add the following methods to TypeInfo.cs
        private static IEnumerable<Type> SearchableTypes(Type t)
        {
            if (t.IsInterface)
            {
                foreach (Type @interface in SearchInterfaces(t))
                {
                    yield return @interface;
                }
            }
            else
            {
                foreach (Type baseType in SearchBaseTypes(t))
                {
                    yield return baseType;
                }
            }
        }

        private static IEnumerable<Type> SearchBaseTypes(Type t)
        {
            yield return t;
            t = t.BaseType;
            if (t != null)
            {
                foreach (Type baseType in SearchBaseTypes(t))
                {
                    yield return baseType;
                }
            }
        }

        public static IEnumerable<Type> SearchInterfaces(Type t)
        {
            yield return t;
            foreach (Type @interface in t.GetInterfaces())
            {
                foreach (Type baseInterface in SearchInterfaces(@interface))
                {
                    yield return baseInterface;
                }
            }
        }

in the Find* (FindField,FindProperty,FindEvent,FindMethod) Methods change the 
following lines
        for (; t != null; t = t.BaseType)
to
        foreach (Type type in SearchableTypes(t))

In TypeGen.cs change the ScanMethodsToImplement method to
    void ScanMethodsToImplement(Type[] interfaces)
    {
        if (interfaces == null)
        return;

        foreach (Type t in interfaces)
        {
                foreach (Type @interface in TypeInfo.SearchInterfaces(t))
                {
                    foreach (IMemberInfo mi in TypeInfo.GetMethods(@interface))
                        implementations.Add(new InterfaceImplEntry(mi));
        }
        }
    }

Fix for Issue 3:

Add this method to TypeGen.cs
        public DelegateGen Delegate(Type returnType, string name)
        {
            DelegateGen dg = new DelegateGen(this, name, returnType, (typeVis | typeVirt | typeFlags | TypeAttributes.Class | TypeAttributes.Sealed) ^ TypeAttributes.BeforeFieldInit);
            ResetAttrs();
            return dg;
        }   
Add this field to DelegateGen.cs
        TypeGen owner2;
Add this constructor to DelegateGen.cs
        public DelegateGen(TypeGen typeGen, string name, Type returnType, TypeAttributes typeAttributes)
            : base(returnType)
        {
            this.owner2 = typeGen;
            this.name = name;
            this.attrs = typeAttributes;
        }
Change the first Lines in ImplementDelegate() (DelegateGen.cs)
from
        TypeGen tg = new TypeGen(owner, name, attrs, typeof(MulticastDelegate), Type.EmptyTypes);
to
        TypeGen tg;
            if (owner == null)
            {
                tg = new TypeGen(owner2, name, attrs, typeof(MulticastDelegate), Type.EmptyTypes);
            }
            else
            {
                tg = new TypeGen(owner, name, attrs, typeof(MulticastDelegate), Type.EmptyTypes);
            }

Fix for issue 4:

Add the following method to TypeGen.cs

        public EventGen EventImplementation(Type interfaceType, Type eventHandlerType, string name)
        {
            if (tb.IsInterface)
                throw new InvalidOperationException(Properties.Messages.ErrInterfaceNoExplicitImpl);

            EventGen eg = new EventGen(this, name, eventHandlerType,
                MethodAttributes.Private | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final);
            eg.ImplementedInterface = interfaceType;
            return eg;
        }
Add the following to EventGen.cs

    private Type interfaceType;
        void LockSignature()
        {
            if (eb == null)
            {
                eb = owner.TypeBuilder.DefineEvent(interfaceType == null ? name : interfaceType.FullName + "." + name, EventAttributes.None, type);
                owner.RegisterForCompletion(this);
            }
        }

        internal Type ImplementedInterface
        {
            get { return interfaceType; }
            set { interfaceType = value; }
        }

Change the EventGen constructor to:
    internal EventGen(TypeGen owner, string name, Type type, MethodAttributes mthAttr)
    {
        this.owner = owner;
            this.name = name;
        this.type = type;
        this.attrs = mthAttr;
    }
And the EventGen.AddMethod(string) and EventGen.RemoveMethod(string) to

        public MethodGen AddMethod(string parameterName)
        {
            if (adder == null)
            {
                LockSignature();
                adder = new MethodGen(owner, "add_" + name, attrs | MethodAttributes.SpecialName, typeof(void), 0);
                adder.ImplementedInterface = interfaceType;
                adder.Parameter(type, parameterName);
                eb.SetAddOnMethod(adder.GetMethodBuilder());
            }

            return adder;
        }

        public MethodGen RemoveMethod(string parameterName)
        {
            if (remover == null)
            {
                LockSignature();
                remover = new MethodGen(owner, "remove_" + name, attrs | MethodAttributes.SpecialName, typeof(void), 0);
                remover.ImplementedInterface = interfaceType;
                remover.Parameter(type, parameterName);
                eb.SetRemoveOnMethod(remover.GetMethodBuilder());
            }

            return remover;
        }

I hope these changes are fitting in your library and do not break something ;). 
They are working for me at least.
And i hope someone saves some time with this post, instead of investigating the 
issues. 

I really want to thank you for this amazing library ... If i had not found your 
library i think i would code exactly the same thing :) 
You saved me really a lot of time (except for this issues it was not always 
easy to track them down, and find the right solution ;) )
If somebody can see a breaking change or something like this please feel free 
to post here.

Original issue reported on code.google.com by matth...@googlemail.com on 25 Sep 2010 at 1:41

Attachments: