首页 > 解决方案 > 查找实现接口的类,使用反射,并在 F# 中实例化它们

问题描述

我正在努力实现以下目标:

我有一个名为IBotCommand的接口和一些实现它的类。我想通过反射找到所有这些类,实例化每个类的实例并将结果放入字典中。

界面如下:

type IBotCommands =

    abstract member Name: unit -> string
    abstract member Description: unit -> string
    abstract member Help: unit -> string
    abstract member Execute: MessageEventArgs -> string[] -> string

和代码:

let t = typeof<IBotCommands>
t.Assembly.GetTypes()
 |> Seq.filter (fun x -> x.IsSubclassOf(t))
 |> Seq.iter (fun x ->
     (
         let i = Activator.CreateInstance(x) :> IBotCommands
         botCommands.[i.Name] <- i
     )
 )

我遇到的问题是 CreateInstance 行。CreateInstance 返回一个无法转换为 IBotCommands的obj类型。

我在 C# 中也有同样的功能,它可以正常工作,但 C# 版本正在使用动态:

    public static IEnumerable<Type> FindClassSubclassOfType<T>()
    {
        var a = typeof(T)
                .Assembly.GetTypes()
                .Where(t => t.IsSubclassOf(typeof(T)))
                .Select(t => t);

        return a.ToList();
    }

    var types = ReflectionHelper.FindClassSubclassOfType<BotCommand>();
    foreach (var t in types)
    {
        dynamic c = Activator.CreateInstance(t);
        BotCommands[c.Name] = c;
    }

我怎样才能让这种行为在 F# 中起作用?

您可以将对象强制转换为 F# 中的接口吗?这是我第一次在 F# 中使用接口

标签: f#

解决方案


a :> T在 F# 中, upcast 和 downacst是有区别的a :?> T

  • 当编译器静态知道a实现了一个接口时,使用 Upcast T。如果您有一个具体类的值并且想要获得一个具有接口类型的值,这将很有用。

  • 当编译器不能静态知道是否a实现了接口时,使用向下转换。换句话说,这意味着强制转换可能会失败。

在您的情况下,您需要向下转换,因为编译器不知道是否obj实现了IBotInterface. 您需要做的就是添加?

let i = Activator.CreateInstance(x) :?> IBotCommands
botCommands.[i.Name] <- i

推荐阅读