ekonbenefits / impromptu-interface

Static interface to dynamic implementation (duck casting). Uses the DLR combined with Reflect.Emit.
Apache License 2.0
655 stars 67 forks source link

ActLike() fails with explicit interface implementation #36

Open piedar opened 4 years ago

piedar commented 4 years ago

I'm not sure if this is expected behavior.

interface IDo
{
    void Do();
}

sealed class DoNothing : IDo
{
    void IDo.Do() { }
}
class TheDoNothing
{
    [Test]
    public void CanActLike()
    {
        var instance = new DoNothing();
        var acting = instance.ActLike<IDo>();
        acting.Do(); // throws RuntimeBinderException
    }
}

I read about Dynamitey UsagePrivate but this produces the same result.

class TheDoNothing
{
    [Test]
    public void CanActLike()
    {
        var instance = new DoNothing();
        var context = new InvokeContext(instance, typeof(IDo));
        var acting = context.ActLike<IDo>();
        acting.Do(); // throws RuntimeBinderException
    }
}

Obviously this a toy example, but I'm running into real issues when trying to do something similar using DynamicActLike() with an interface type known only at runtime.

jbtule commented 4 years ago

Yeah, with this toy example, I'd just test to see if instance already implements IDo and not run ActLike.

If it's not the same interface, explicit interfaces are very tricky, because the methods names are all qualified. How do I know what the name of the interface you are intending, I'd have do an exhaustive search with reflection,

piedar commented 4 years ago

My use case is to make an instance loaded from one AssemblyLoadContext act like an interface loaded from a different AssemblyLoadContext. It is the same interface by name, but technically a different Type because it comes from a different load context. This looks something like

// find a matching Type from the assemblies loaded with the Provider's AssemblyLoadContext
Type resolvedType = ResolveType(serviceType);
object resolvedService = Provider.GetService(resolvedType);
var result = ImpromptuInterface.Impromptu.DynamicActLike(resolvedService, serviceType);

This almost works great, except that when the serviceType is Microsoft.Extensions.Logging.Abstractions.ILogger<T> the Provider produces a Logger<T> which has explicit implementations of the interface methods.