我正在努力实现以下目标:
我有一个名为 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#中使用接口
答案 0 :(得分:3)
在F#中,上流a :> T
和下流a :?> T
之间是有区别的。
a
实现接口T
时,使用Upcast。如果您有一个具体类的值,并且想要获得一个具有接口类型的值,这将很有用。
当编译器不能静态地知道a
是否实现接口时,使用Downcast。换句话说,这意味着转换可能会失败。
在您的情况下,您需要向下转换,因为编译器不知道obj
是否实现IBotInterface
。您需要做的就是添加?
:
let i = Activator.CreateInstance(x) :?> IBotCommands
botCommands.[i.Name] <- i