有一个像这样的 C# 类
public abstract class ValueAttrProxy<T> : IAttrProxy where T : IEquatable<T>
{
public T Value { get; }
...
}
在 F# 中,当我尝试像这样进行模式匹配时:
let attrValue (attr:IAttrProxy) =
match attr with
| :? ValueAttrProxy<'a> as attr -> attr.Value.ToString()
类型推断似乎有效,但发送到交互式失败并出现以下错误:
错误 FS0071:对类型推断变量应用默认类型“IEquatable<'a>”时,类型约束不匹配。类型 ''a' 和 'IEquatable<'a>' 无法统一。考虑添加更多类型约束
我有点困惑到底是什么问题,或者额外的类型注释在哪里。
尝试在匹配模式中指定 IEquatable<'a>
| :? ValueAttrProxy<IEquatable<'a>> as attr -> attr.Value.ToString()
然后,即使类型推断也会失败,并用相同的错误消息在模式下划线。 如果我将泛型参数限制为特定类型(例如 int),那么它就可以工作,但重点是我只想要值的字符串表示形式,而不管其实际类型是什么。
最佳答案
问题是当你写:? ValueAttrProxy<'a>
时,编译器需要推断 'a
的类型静态地。这不是在运行时根据值确定的类型。如果没有限制,编译器仍然会愉快地编译它,但它将使用 obj
作为默认类型 'a
.
这个问题和最近在pattern matching against seq<'a>
上的一个问题基本相同你有完全相同的问题。那里的答案展示了如何使用反射解决问题,这也适用于您的情况。
如果您可以控制 C# 类,那么添加 BoxedValue
会容易得多但非通用接口(interface)的属性:
public interface IAttrProxy {
public object BoxedValue { get; }
// (...)
}
public abstract class ValueAttrProxy<T> :
IAttrProxy where T : IEquatable<T> {
public T Value { get; }
// (...)
}
然后您可以仅与 IAttrProxy
进行模式匹配并直接访问该值:
let attrValue (attr:IAttrProxy) =
attr.BoxedValue.ToString()
关于F# 对具有类型约束的泛型类进行模式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62654464/