【问题标题】:Get type that implements generic interface by searching for a specific generic interface parameter通过搜索特定的泛型接口参数获取实现泛型接口的类型
【发布时间】:2018-05-26 12:13:23
【问题描述】:

我想创建一个返回类型(或 IEnumerable 类型)的方法,该类型实现采用类型参数的特定接口——但是我想通过该泛型类型参数本身进行搜索。这更容易举例说明:

我想要的方法签名:

 public IEnumerable<Type> GetByInterfaceAndGeneric(Type interfaceWithParam, Type specificTypeParameter)

然后如果我有以下对象

  public interface IRepository<T> { };
  public class FooRepo : IRepository<Foo> { };
  public class DifferentFooRepo : IRepository<Foo> {};

然后我希望能够做到:

  var repos = GetByInterfaceAndGeneric(typeof(IRepository<>), typeof(Foo));

并获得一个包含FooRepoDifferentFooRepo 类型的IEnumerable。

这与this question 非常相似,但是使用该示例我想同时搜索IRepository&lt;&gt;User

【问题讨论】:

  • 您的问题确实可以通过使用GetAllTypesImplementingOpenGenericType 接受的答案完全解决,您只需在x.GenericTypeArguments[0].IsAssignableFrom(specificTypeParameter) 的每个if 中添加一个条件,以检查特定的类型参数。跨度>
  • 只要var closedType = interfaceWithParam.MakeGenericType(specificTypeParameter)。那么你的任务就变成了“找到所有实现特定接口的类型”。
  • 我会说它甚至是这个问题和类似问题的重复:stackoverflow.com/q/26733/5311735
  • @ScottChamberlain 你能详细说明一下吗?我知道我对此很接近,但我应该在哪里添加这些条件?使用您提出的解决方案,我似乎无法使其正常工作。
  • 我认为这不是 stackoverflow.com/q/26733/5311735 的副本。虽然这个链接的问题很相似,但我的问题是特定于通过实际的通用接口参数进行搜索的。我在研究中确实遇到了这个问题,但对我来说差异并不小,因为没有@Rainman 提供的答案,我无法解决我的问题。

标签: c# .net reflection


【解决方案1】:

为了重构@lucky 的答案,我更喜欢将类型与泛型类型定义进行比较,而不是使用类型名称:

static readonly Type GenericIEnumerableType = typeof(IEnumerable<>);

//Find all types that implement IEnumerable<T>
static IEnumerable<T> FindAllEnumerableTypes<T>(Assembly assembly) =>
  assembly
  .GetTypes()
  .Where(type =>
    type
      .GetInterfaces()
      .Any(interf =>
        interf.IsGenericType
        && interf.GetGenericTypeDefinition() == GenericIEnumerableType
        && interf.GenericTypeArguments.Single() == typeof(T)));

或者,您可以检查interf 是否可以从GenericIEnumerableType.MakeGenericType(typeof(T)) 分配,或者相反。

【讨论】:

    【解决方案2】:

    你可以这样试试;

        public static IEnumerable<Type> GetByInterfaceAndGeneric(Type interfaceWithParam, Type specificTypeParameter)
        {
            var query =  
                from x in specificTypeParameter.Assembly.GetTypes()
                where 
                x.GetInterfaces().Any(k => k.Name == interfaceWithParam.Name && 
                k.Namespace == interfaceWithParam.Namespace && 
                k.GenericTypeArguments.Contains(specificTypeParameter))
                select x;
            return query;
        }
    

    用法

    var types = GetByInterfaceAndGeneric(typeof(IRepository<>), typeof(Foo)).ToList();
    

    【讨论】:

    • 这似乎在示例实现中运行良好。但是有一个问题——如果我的接口和 specificTypeParameter 位于不同的程序集中,类似的方法是否仍然有效?显然,我必须稍微更改查询,但假设我希望能够处理该用例,这仍然是您推荐的方法吗?
    • 是的,您可以通过稍微更改查询来处理不同的程序集。我建议您指定包含存储库的程序集。那么,这是正确的方法吗?我不知道,我不能建议正确的方法,因为我不知道需求和项目设计。但是,至少我可以建议您,如果不是必须的,只需为每个实体创建一个存储库。
    • 当然有道理。上面的解释其实和我的实际实现相差甚远,我只是想把它简单地说一下,让它有关联。在我的实际用例中,我尝试使用自定义模型创建器根据许多条件从一些输入数据创建和配置域模型,这样我的域模型中就没有任何数据逻辑。我希望能够使用反射(他们实现 IGenerator)来获取模型创建者,所以这就是我这样做的方式。
    猜你喜欢
    • 1970-01-01
    • 2010-11-11
    • 2014-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-22
    相关资源
    最近更新 更多