none
Let one assembly implement an internal interface of the caller RRS feed

  • Question

  • I've created one of these nifty proxy creators that implments an interface for you. It works fine on public interfaces, but for internal interfaces i run into trouble. The Proxy class resides in its own assembly, and has the following simple usage:

    Type impl = Proxy.Create(Type interfaceType);

    Above method will create it's own dynamic assembly and if the caller supplies an internal interface type, TypeBuilder.CreateType will throw an exception. I thought I could somehow remidy this by letting the caller also supply the ModuleBuilder used to host the type:

    Type impl = Proxy.Create(Type interfaceType, ModuleBuilder mb);

    However I havn't got this to work. Any idéas? How do I let one assembly implement an internal interface of the caller?
    Thursday, December 4, 2008 11:13 AM

All replies

  • Document your problem.  Paste the exception message, the stack trace and a snippet of the code that causes it.
    Hans Passant.
    Thursday, December 4, 2008 11:18 AM
    Moderator
  • nobugz said:

    Document your problem.  Paste the exception message, the stack trace and a snippet of the code that causes it.


    Hans Passant.

    Ok, I'll try but it will be a long post...

    The library to create proxies resides in it's own dll, the main class is Proxy which has static methods to create interface implementations:

            public static Type GetProxy(Type interfaceType)
            {
                Type proxyT = null; 
                if ( !proxyCache.TryGetValue(interfaceType.FullName, out proxyT) )
                {
                    AssemblyName aName = new AssemblyName("ProxyAssembly");
                    AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
                    ModuleBuilder mb = ab.DefineDynamicModule("ProxyModule");
                    proxyT = CreateProxy(interfaceType, mb);
                    proxyCache[interfaceType.FullName] = proxyT;
                }
                return proxyT;
            }

    public static Type CreateProxy(Type interfaceType, ModuleBuilder mb)
            {
                if (!interfaceType.IsInterface)
                    throw new ArgumentException("First argument must be an interface type", "interfaceType");

                // Create TypeBuilder
                TypeBuilder tb = mb.DefineType(interfaceType.Name + "ProxyImpl", TypeAttributes.Public, typeof(Proxy));
                tb.AddInterfaceImplementation(interfaceType);

        [ .. heaps of emit code to implement the interface ..]

        return tb.CreateType();
    }

    Now, a usage example. Another application:

        class Program
        {
            static void Main(string[] args)
            {

                Type ITestImplType = Proxy.GetProxy(typeof(ITest));

            }

       }
       public interface ITest
       {
           void someMethod(int i, out float fo);
       }

    Above works fine. But if I change the access of ITest to internal, tb.CreateType() will throw the following exception:

    System.TypeLoadException was unhandled
      Message="Type 'ITestProxyImpl' from assembly 'ProxyAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is attempting to implement an inaccessible interface."
      Source="mscorlib"
      TypeName="ITestProxyImpl"
      StackTrace:
           at System.Reflection.Emit.TypeBuilder._TermCreateClass(Int32 handle, Module module)
           at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
           at System.Reflection.Emit.TypeBuilder.CreateType()
           at Litium.Util.Proxy.CreateProxy(Type interfaceType, ModuleBuilder mb) in C:\projekt\proxy\Litium.Util\Proxy.cs:line 76
           at Litium.Util.Proxy.GetProxy(Type interfaceType) in C:\projekt\proxy\Litium.Util\Proxy.cs:line 28
           at test.Program.Main(String[] args) in C:\projekt\proxy\test\Program.cs:line 15
           at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           at System.Threading.ThreadHelper.ThreadStart()
      InnerException: 

    How can remedy this? As you can see the Proxy class also has a method which takes an instance of ModuleBuilder to use for creating the type. Can I somehow make a ModuleBuilder which has access to internal members of the assembly who created it? Sortof setting the InternalsVisibleTo attribute at runtime and pointing it to a dynamic assembly just created?

    Edit:
    I just tried to actually use the InternalsVisibleTo("ProxyAssembly") attribute on my application and then it works fine. I thought one always had to use strongly named assemblies to use InternalsVisibleTo. When thats not the case I guess the solution is simple enough. Still if someone knows a way to achive the same without InternalsVisibleTo that would be intresting to hear.
    Thursday, December 4, 2008 12:50 PM