首页 > 解决方案 > 如何在上下文中动态指定方法的泛型类型(如果可能,不进行反射)

问题描述

那么是否可以在 C# 中为方法动态指定泛型类型?我不是在谈论使用反射,而是仅使用 C#。

例子:

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
}

现在我的问题是我将提供一个string“foo”,internal class Foo因为Foo它是内部的,我的其他项目无法访问(这是预期的)。但它在外部被称为string“foo”。

现在我想调用以下方法(这是公共的)。

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?
}

因为泛型T正在访问一个DbSet类型,T所以我需要能够在上下文中提供它。

那么我该如何解决这个难题呢?反思是不被禁止的,但我想知道是否有一种“原生”的方式。或者一种体面的反思方式

编辑1:

WhateverClass与 有相关性IEntity。假设我想根据 abool是否IEntity在集合中来设置 a 。这被抽象了很多,但是在这里键入所有上下文是没有用的。

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

标签: c#genericsreflection

解决方案


一种选择是使用从 switch 表达式调用的通用方法。为简洁起见,这可以是一种嵌套方法。这样可以避免重复,也可以避免反思。例如:

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);
}

您仍然需要 switch 表达式,但它可能比使用反射更好。


推荐阅读