Search code examples
c#reflectiondefault-interface-member

C# 9 - How to call default interface method with reflection?


I have an interface for automapper. And DTOs implement this interfaces. As you can see there is a default method.

public interface IMap<T> {
    public void Mapping(Profile profile) {
        profile.CreateMap(typeof(T), GetType()).ReverseMap();
    }
}

public class ItemDto : IMap<Item> {
    public string Name { get; set; }
}

When I try to invoke this method. The method cannot be found.

public class MappingProfile : Profile {
    public MappingProfile() {
        ApplyMappingsFromAssembly();
    }

    private void ApplyMappingsFromAssembly() {
        var types = AppDomain.CurrentDomain.GetAssemblies().Where(w => !w.IsDynamic).SelectMany(s => s.GetExportedTypes())
            .Where(t => t.GetInterfaces().Any(i =>
                i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMap<>)))
            .ToList();

        foreach (var type in types) {
            var instance = Activator.CreateInstance(type);
            var methodInfo = type.GetMethod("Mapping");
            //In here I expect to call default interface method.
            methodInfo?.Invoke(instance, new object[] { this });
        }
    }
}

How can I call default interface method?


Solution

  • You need to invoke the method against the interface, that includes getting the method with reflection too. For example:

    // Create the IMap<Item> type
    var mapType = typeof(IMap<>).MakeGenericType(typeof(Item));
    
    // Create the instance as you did before
    var instance = Activator.CreateInstance(typeof(ItemDto));
    
    // Get the method from the interface
    var method = mapType.GetMethod("Mapping");
    
    // Invoke the method
    method.Invoke(instance, new object[] { ... });
    

    To fit this into your code, it would look something like this:

    foreach (var type in types)
    {
        // Cheating here by getting the first interface, so you might want to be cleverer
        var mapInterface = type.GetInterfaces()[0];
        
        // Get the generic type of the interface, e.g. "Item"
        var genericType = mapInterface.GetGenericArguments()[0];
        
        var instance = Activator.CreateInstance(type);
        var mapType = typeof(IMap<>).MakeGenericType(genericType);
        var methodInfo = mapType.GetMethod("Mapping");
    
        methodInfo?.Invoke(instance, new object[] { this });
    }