How to specify generic type for method dynamically in context (without reflection if possible)

So is it possible to specify a generic type for a method dynamically in C#? I am not talking about using reflection, but with just C#.

Example:

internal class MyRepository
{
  async Task<IEnumerable<WhateverClass>> GetItemsFor<T>(int entityId, int itemId, params string[] keys)
    where T : class, IEntity
  {
    // do whatever
  }
}

interface IEntity
{
  public int Id { get; set; }
}

internal class Foo : IEntity
{
  // whatever
}

Now my problem is that I will supply a string “foo” as internal class Foo because Foo is internal and cannot be accessed by my other projects (which is intended). But it is externally known as string “foo”.

Now I want to call following method (which is public).

public async Task<IEnumerable<WhateverClass>> GetItemsFor(string forAsString, int entityId, int itemId, params string[] keys)
{
  var forAsType = forAsString switch
  {
     "foo" => typeof(Foo) // or what is needed here
  };

  return await _myRepository.GetItemsFor<forAsType>(entityId, itemId, keys); // this is not possible. How can I make this work?
}

Because the generic T is accessing a DbSet of type T I need to able to supply this in context.

So how can I solve this puzzle? Reflection is not forbidden but I am wondering if there is a “native” way. Or a respectable way with reflection

Edit 1:

WhateverClass has a correlation to IEntity. Let’s say I want to set a bool based on if the IEntity is in a collection. This is abstracted a lot, but it is of no use to type all the context here.

public class WhateverClass
{
  public bool Enabled { get; set }
}

Answer

One option would be to use a generic method which you call from your switch expression. That can be a nested method for brevity. That would avoid duplication, but also avoid reflection. For example:

public Task<IEnumerable<WhateverClass>> GetItemsFor(
    string forAsString, int entityId, int itemId, params string[] keys)
{
    return forAsString switch
    {
       "foo" => Impl<Foo>(),
       "bar" => Impl<Bar>(),
       _ => throw new ArgumentException($"Unknown 'for' value: {forAsString}");
    };

    async Task<IEnumerable<WhateverClass>> Impl<T>() =>
        await _myRepository.GetItemsFor<T>(entityId, itemId, keys);
}

You still need the switch expression, but it’s probably nicer than using reflection.