查找实现接口的类,使用反射并在F#中实例化它们

时间:2020-01-21 23:43:55

标签: 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#中使用接口

1 个答案:

答案 0 :(得分:3)

在F#中,上流a :> T和下流a :?> T之间是有区别的。

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

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

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

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