11

Suppose I have assembly that declares internal interface IInternalInterface. I have no access to code of this assembly and I can't change it. How can I create my own implementation of IInternalInterface?

Why I need this: the assembly contains the class with list of IInternalInterface implementers and my goal is to add my own implementation there.

Denis Palnitsky
  • 18,267
  • 14
  • 46
  • 55

6 Answers6

9

It is possible using remoting proxy.
Note that my answer is just a quick sketch and might need to be improved further.

internal interface IInternalInterface {
    void SayHello();
}

// --------------------------------------------------------------
// in another assembly
public class ImplementationProxy : RealProxy, IRemotingTypeInfo {
    private readonly MethodInfo method;

    public ImplementationProxy(MethodInfo method) 
        : base(typeof(ContextBoundObject))
    {
        this.method = method;
    }

    public override IMessage Invoke(IMessage msg) {
        if (!(msg is IMethodCallMessage))
            throw new NotSupportedException();

        var call = (IMethodCallMessage)msg;
        if (call.MethodBase != this.method)
            throw new NotSupportedException();

        Console.WriteLine("Hi from internals!");
        return new ReturnMessage(null, null, 0, call.LogicalCallContext, call);
    }

    public bool CanCastTo(Type fromType, object o)
    {
        return fromType == method.DeclaringType;
    }

    public string TypeName
    {
        get { return this.GetType().Name; }
        set { }
    }
}    
Andrey Shchekin
  • 21,101
  • 19
  • 94
  • 162
3

I will extend the answer from @AndreyShchekin as it was really useful but missed some bits:

public class Program
{
    public static void Main()
    {
        var internalType = typeof(PublicTypeInAnotherAssembly).Assembly.GetType("Full name of internal type: System.Internals.IInterface");

        var result = new InterfaceImplementer(internalType, InterfaceCalled).GetTransparentProxy();
    }

    static object InterfaceCalled(MethodInfo info)
    {
        // Implement logic.
        Console.WriteLine($"{info.Name}: Did someone call an internal method?");
        // Return value matching info.ReturnType or null if void.
        return null;
    }
}

public class InterfaceImplementer : RealProxy, IRemotingTypeInfo
{
    readonly Type _type;
    readonly Func<MethodInfo, object> _callback;

    public InterfaceImplementer(Type type, Func<MethodInfo, object> callback) : base(type)
    {
        _callback = callback;
        _type = type;
    }

    public override IMessage Invoke(IMessage msg)
    {
        var call = msg as IMethodCallMessage;

        if (call == null)
            throw new NotSupportedException();

        var method = (MethodInfo)call.MethodBase;

        return new ReturnMessage(_callback(method), null, 0, call.LogicalCallContext, call);
    }

    public bool CanCastTo(Type fromType, object o) => fromType == _type;

    public string TypeName { get; set; }
}

Now result is assignable to the internal interface. To verify it, we can do this in the assembly containing the internal interface:

public class PublicTypeInAnotherAssembly
{
    public void Test(object proxy)
    {
        var internalInterface = (IInternalInterface)proxy;

        internalInterface.MethodOnInterface();
    }
}

Or assign it with reflection if we don't have access.

Stefano d'Antonio
  • 5,874
  • 3
  • 32
  • 45
3

How can I to create my own implementation of IInternalInterface?

Simple answer: you can't. If the authors of the assembly decided to mark this interface with internal it means that they didn't want code from other assemblies to use this interface.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
0

You could also use assembly version redirection or type redirection to "move" the interface declaration to an assembly under your control and make your implementation public.

But as Darin said, be sure to double-think about this approach. There may be an intended way to extend the library functionality that would be much cleaner...

eFloh
  • 2,098
  • 20
  • 24
  • What is version redirection or type redirection? – Denis Palnitsky Dec 22 '11 at 16:12
  • @Orsol: Google is pure Magic! here: http://msdn.microsoft.com/en-us/library/7wd6ex19(v=vs.71).aspx and http://msdn.microsoft.com/en-us/library/ms404275.aspx – Stefan Paul Noack Dec 22 '11 at 16:22
  • @Orsol: You could make a "fake" assembly that redirects everything to the original one but adds your interface implementation. Not sure if this works but even if it does it's quite a dirty hack. – Stefan Paul Noack Dec 22 '11 at 16:35
  • Wouldn't it be possible to redirect only the interface to a newly created assembly and make it public there? but as said, welcome to the dark side ;) – eFloh Dec 23 '11 at 09:13
0

I am afraid this is impossible. Even if you manage to make a class that implements that interface using Reflection.Emit, you won't be able to use it because you will get a ReflectionTypeLoadException: Type is attempting to implement an inaccessible interface

Community
  • 1
  • 1
Stefan Paul Noack
  • 3,654
  • 1
  • 27
  • 38
-1

You could add [InternalsVisibleTo()] attribute, but as far as you have no access to source code, you can't implement this interface at compile time

From the other hand, you can do it at run time. For this you should use runtime code generation (also known as Reflection.Emit) and fetch the interface type with BindingFlags.NonPublic. You can read more about it here.

UPDATED:
As mentioned in comments below, it is impossible to inherit from a non-public interface. So unfortunately you have no solutions.

Community
  • 1
  • 1
Alexander Yezutov
  • 3,144
  • 2
  • 21
  • 23
  • Nope. I thought that would work, but it [doesn't](http://stackoverflow.com/questions/4350363/reflectiontypeloadexception-type-is-attempting-to-implement-an-inaccessible-int). – Stefan Paul Noack Dec 22 '11 at 16:14