c# - 当从 C# 应用程序调用时,为什么在 f# 中实现的类型与 C# 类型的行为不同?
问题描述
我正在将我的 C# 代码移植到 F# 库中。我的 C# 库中有以下接口/类:
public interface IMatch<out T> where T : IGame
{
IEnumerable<T> Games { get; }
}
public interface IGame
{
string Name { get; }
}
public class SoccerMatch : IMatch<SoccerGame>
{
public SoccerMatch(IEnumerable<SoccerGame> games)
{
Games = games;
}
public IEnumerable<SoccerGame> Games { get; }
}
public class SoccerGame : IGame
{
public SoccerGame(string name)
{
Name = name;
}
public string Name { get; }
}
我试图将它移植到 F#,这就是我想出的:
type IGame =
abstract member Name: string with get
type IMatch<'T when 'T :> IGame> =
abstract member Games: IEnumerable<'T> with get
type SoccerGame =
{Name: string}
interface IGame with
member this.Name with get() = this.Name
type SoccerMatch =
{ Games: IEnumerable<SoccerGame>}
interface IMatch<SoccerGame> with
member this.Games: IEnumerable<SoccerGame> = this.Games
问题是,我需要从我的 C# 应用程序中调用这个 F# 库。之前,在使用 C# 类时,我可以执行以下操作:
var match= new SoccerMatch(new List<SoccerGame>());
IMatch<IGame> interfaceType = match;
但是当我尝试对我的 F# 库做同样的事情时:
var match = new SoccerMatch(new List<SoccerGame>());
IMatch<IGame> interfaceType = match;
我收到以下错误:错误 CS0029 无法将类型“FSharp.SoccerMatch”隐式转换为“FSharp.IMatch”
我认为我的 F# 实现中一定有问题(显然),但是什么?
解决方案
您的 F# 类型与 C# 类型的行为不同,因为它与 C# 类型不同。C# one 的T
参数声明为“out”:
public interface IMatch<out T> where T : IGame
这out
意味着类型参数T
是协变的,这正是允许从SoccerMatch
(即IMatch<SoccerGame>
) 到IMatch<IGame>
.
但是,据我所知,F# 不支持泛型接口中的协变\逆变。多年来一直有人建议,但问题仍然存在。所以你的 F# 接口类似于这个 C# 接口:
public interface IMatch <T> where T : IGame
{
IEnumerable<T> Games { get; }
}
这将产生相同的编译时错误。
推荐阅读
- flutter - Flutter:如何同步 TOTP 代码?
- python - 将时间指定为“base_time”的偏移量时合并 netCDF 文件
- javascript - Moodle Web Service如何获取itemid
- macos - 有没有办法在 macOS 上显示“选择文件夹”对话框?
- sql - 使用 SPARK SQL 删除重复项
- neural-network - RuntimeError:尝试第二次向后遍历图形,但保存的中间结果已被释放
- r - 需要在 2000 年代制作我的日期并在 R 中创建“June-2000”
- javascript - 如何使用 clearTimeout 功能实现承诺的 setTimeout?
- turbolinks - Hotwire Turbo 不会取代涡轮框架
- python - python在可散列对象上设置差异