c#测试一个对象是否使用.GetType()实现任何Type的ISurface <t> .GetInterface(typeof(ISurface&lt;&gt;)。FullName)</t>

时间:2013-11-04 19:03:24

标签: c# linq generics interface

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

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

编辑:关于对接口名称进行硬编码,我认为如果名称是从实际界面直接提取的话,这些问题会得到缓解,正如Tim在下面提到的那样: < / p>

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

使用 .FullName ,名称空间歧义也应该没有问题。除了硬编码,我主要对方法本身感兴趣,因为它看起来比通过一系列类型属性检查/ LINQ语法更简洁。然后,我不知道幕后发生了什么。

5 个答案:

答案 0 :(得分:2)

以下是如何提取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扩展名。)

答案 1 :(得分:0)

如果只检查接口的“简单”名称(而不是完全指定的类名,包括名称空间),那么如果在另一个名称空间中有另一个具有相同名称的接口,则会遇到问题。

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

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

当然,如果是最好的方法,可以辩论。如果更改界面名称,则会出现问题。

答案 2 :(得分:0)

嗯,这是一个可能会发生变化的实施细节。另外,你安全地失去了运行时类型。我宁愿坚持使用 public 方法 - 使用你发现的Linq或使用反射。

答案 3 :(得分:0)

有几个原因可以解释为什么你可能不想这样做:

  1. 如果您重构代码以使"ISurface`1"不再有效(例如添加或删除类型参数或重命名接口),编译器将无法捕获它。这可以通过将其替换为typeof(ISurface<>).Name来解决。
  2. 如果在另一个命名空间中有ISurface<>,则它是不明确的(或者,至少,乍一看似乎是这样)。
  3. 我可能会使用您链接的the solution,也可能用扩展方法包装,以便我可以更简单地调用它,例如。

    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
    

答案 4 :(得分: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语法之类的东西作为创建委托的快捷方式),但实现的方法可以做某事比如将提供的工厂的引用存储到静态泛型类的字段中而不使用Reflection,这是委托无法做到的事情。