0

I have an empty IContext inteface:

public interface IContext {
}

I also have two derived interfaces IBasicContext and ITypedContext:

public interface IBasicContext : IContext {
    string Id { get; }
}

public interface ITypedContext<T> : IContext {
    T Value { get; }
}

I have another project with some code that processes these contexts:

internal static ProcessedContext Process(this IContext context) {
    if (context is IBasicContext basicContext) {
        return basicContext.Process();
    } else if (context.GetType().IsAssignableFrom(typeof(ITypedContext<>))){
        // What do I do here??
    }
}

internal static ProcessedContext Process(this IBasicContext context) {
    // Do stuff here to create processed context
}

internal static ProcessedContext Process<T>(this ITypedContext<T> context) {
    // Do stuff here to create processed context
}

Note 1: I have already checked multiple posts. Most of them ask about casting to a base generic class, which is NOT what I am trying to do here.

Note 2: Context classes sit in their own project. They are merely data structures and ProcessedContext creation code does not belong in context project.

Note 3: T can be one of multiple types that I only create at runtime. Having multiple cases for each type is just daunting and ugly. The processing of ITypedContext does not really care about T. It calls another generic method.

H K
  • 87
  • 8
  • @RyanWilson which method are we talking about? – H K Aug 29 '18 at 17:34
  • @GianPaolo It is actually up there. It is calling the static extension method `Process`. – H K Aug 29 '18 at 17:37
  • The Process method, since both objects implement an interface which implements a base interface – Ryan Wilson Aug 29 '18 at 17:53
  • @RyanWilson That does not help. The `Process` methods return `ProcessedContext `types which are objects being created based on the content of the derived types. – H K Aug 29 '18 at 18:01
  • Extension methods are evaluated at compile time, and use only the static type of the object, i.e. the type of the variable **declared**. They do not know or care if the object is actually a derived type. – Ben Aug 29 '18 at 18:16
  • @Ben sure. That's not the issue though. In my specific scenario, I have a derived generic interface that I want to call an extension method on. My particular issue is getting the derived generic instance in the first place to be able to call the extension method. – H K Aug 29 '18 at 18:56

1 Answers1

1

Would this help?

This creates a suitable version of the generic ProcessGeneric<T> method at runtime and invokes it with your runtime instance of ITypedContext<T>.

internal static ProcessedContext Process(this IContext context)
{
    if (context is IBasicContext basicContext)
    {
        return basicContext.Process();
    }
    else if (context.GetType().GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ITypedContext<>)))
    {
        Type typedContextInterface = context.GetType().GetInterfaces().First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ITypedContext<>));

        MethodInfo processGenericMethod = GetType().GetTypeInfo().GetMethod(nameof(ProcessGeneric), BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(typedContextInterface.GetGenericArguments()[0]);

        return (ProcessedContext)processGenericMethod.Invoke(null, new object[] { context });
    }
}

internal static ProcessedContext ProcessGeneric<T>(ITypedContext<T> context)
{
    // Do stuff here to create processed context
}
Thomas Hilbert
  • 3,559
  • 2
  • 13
  • 33
  • Seems like it would. I haven't tested it yet though. But I assume no way around reflection in this case? – H K Aug 29 '18 at 17:41
  • I don't think so. The required method for type T might not even exist yet, but might have to be JIT compiled. – Thomas Hilbert Aug 29 '18 at 17:43
  • By the way, is there a reason for changing the if-condition from `IsAssignableFrom` to what you have in your answer? – H K Aug 29 '18 at 18:02
  • I didn't have time to test it myself and I was sure that the version I wrote did work, so I thought I'd rather use that version. I'm not sure if `IsAssignableFrom` works with generic types that have undefined arguments. – Thomas Hilbert Aug 29 '18 at 18:07
  • Both your check and mine are failing for some reason. I am investigating. – H K Aug 29 '18 at 19:21
  • I had to change the condition to `context.GetType().GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IBasicExpressionContext<>))` which makes sense. – H K Aug 29 '18 at 19:36
  • The `GetMethod` is returning null now though. – H K Aug 29 '18 at 19:37
  • Makes sense to check the interfaces, because the type of the context objext is not exactly the generic interface type, but another type which implements the interface. I didn't think of that. – Thomas Hilbert Aug 29 '18 at 20:02
  • The retrieval of the generic argument had to be changed accordingly, too. See edit. – Thomas Hilbert Aug 29 '18 at 20:18