3

我有一个插件架构,我需要检测所有实现ISurface<T>任何类型接口的插件(即测试ISurface<>)。我看到这里有几个使用 LINQ 的建议(例如这个),我想知道是否有理由支持这个:

.GetType().GetInterface("ISurface`1")

编辑:关于接口名称的硬编码,我认为如果直接从实际接口中提取名称,这些问题会得到缓解,正如 Tim 在下面提到的那样:

.GetType().GetInterface(typeof(ISurface<>).FullName)

命名空间歧义 .FullName 也应该没有问题。除了硬编码,我主要对方法本身感兴趣,因为它看起来比通过一系列类型属性检查 / LINQ 语法更短更清晰。再说一次,我不知道引擎盖下发生了什么。

4

5 回答 5

2

以下是提取所有受支持的 type 接口的方法ISurface<anything>

void Main()
{
    var supportedInterfaces =
        from intf in typeof(Test).GetInterfaces()
        where intf.IsGenericType
        let genericIntf = intf.GetGenericTypeDefinition()
        where genericIntf == typeof(ISurface<>)
        select intf;

    supportedInterfaces.Dump();
}

public class Test : ISurface<int>
{
}

public interface ISurface<T>
{
}

您可以在LINQPad中进行测试(.Dump()扩展方法是 LINQPad 扩展)。

于 2013-11-04T19:18:27.007 回答
0

有几个原因让您想到为什么您可能不想这样做:

  1. 如果你重构你的代码使其"ISurface`1"不再有效(例如添加或删除类型参数或重命名接口),编译器将不会捕获它。这可以通过替换它来解决typeof(ISurface<>).Name
  2. 如果ISurface<>在另一个命名空间中有一个,它是模棱两可的(或者,至少乍一看是这样)。

我可能会使用您链接的解决方案,可能包含在扩展方法中,以便我可以更简单地调用它,例如

public static Type GetInterface(this Type type, Type targetType)
{
    return type.GetInterfaces().SingleOrDefault(t => t.IsGenericType
                          && t.GetGenericTypeDefinition() == targetType);
}
public class Surface : ISurface<int> { /* ... */ }

typeof(Surface).GetInterface(typeof(ISurface<>)); //returns typeof(ISurface<int>)
typeof(NotASurface).GetInterface(typeof(ISurface<>)); //returns null
于 2013-11-04T19:21:06.810 回答
0

如果您对相关接口有任何控制权,我建议您ISurface<T>应该从非泛型ISurface. 该类型又可以包括一个成员,该成员可以以各种方式指示ISurface<T>可用的类型(例如,如果定义了一个接口ITypeRegistrar { Register<TType>(info about type);},则非泛型ISurface可以包括一个RegisterSupportedTypes(ITypeRegistrar registrar)方法。根据与每种类型相关联的确切信息,一个典型的实现可能如下所示:

void RegisterSupportedTypes(ITypeRegistrar registrar)
{
   registrar.Register<Circle>(circleFactory);
   registrar.Register<Square>(squareFactory);
   registrar.Register<Rhombus>(rhombusFactory);
}

客户端代码将接收每个项目作为其实际的泛型类型,因此使用这种方法将允许程序在没有类型转换或反射的情况下运行。因为 .NET 没有开放泛型委托的概念,所以客户端代码必须手动实现ITypeRegistrar接口(而不是使用类似 lambda 语法的东西作为创建委托的快捷方式),但是实现的方法可以做一些事情,比如存储对在不使用反射的情况下将提供的工厂放入静态泛型类的字段中,这是委托无法做到的。

于 2013-11-05T18:59:34.217 回答
0

如果您仅通过接口的“简单”名称(而不是完全指定的类名,包括命名空间)进行检查,那么如果您在另一个命名空间中有另一个同名的接口,那么您将遇到问题。

如果您GetInterface使用完全指定的类名调用该方法,它应该可以正常工作。

MSDN特别提到,对于泛型类型,您应该指定损坏的名称,所以我希望它可以正常工作。

当然,如果是最好的方法,可以商榷。如果更改接口名称,您将遇到问题。

于 2013-11-04T19:17:45.803 回答
0

嗯,这是一个可能会发生变化的实现细节。另外,您可以安全地丢失运行时类型。我宁愿坚持使用公共方法 - 通过使用您发现的 Linq 或使用反射。

于 2013-11-04T19:18:31.197 回答