【问题标题】:casting between C# derived classes, in F#在 C# 派生类之间进行强制转换,在 F# 中
【发布时间】:2021-04-03 15:58:54
【问题描述】:

我有两种来自 C# 库的类型:

一个是这样定义的(只有签名):

public class CallResult<T>: CallResult
{
    public CallResult([AllowNull]T data, Error? error): base(error)
    public static implicit operator bool(CallResult<T> obj)
    public bool GetResultOrError([MaybeNullWhen(false)] out T data, [NotNullWhen(false)] out Error? error)
    public new static WebCallResult<T> CreateErrorResult(Error error)
}

第二个来源于它:

public class WebCallResult<T>: CallResult<T>
{
    public HttpStatusCode? ResponseStatusCode { get; set; }
    public IEnumerable<KeyValuePair<string, IEnumerable<string>>>? ResponseHeaders { get; set; }
    public WebCallResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, [AllowNull] T data, Error? error): base(data, error)
    public WebCallResult(WebCallResult<T> callResult): base(callResult.Data, callResult.Error)
    public static WebCallResult<T> CreateFrom<Y>(WebCallResult<Y> source) where Y : T
    public static WebCallResult<T> CreateErrorResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, Error error)
}

他们都来自:

public class CallResult
{
    public Error? Error { get; internal set; }
    public bool Success => Error == null;
    public CallResult(Error? error)
    public static implicit operator bool(CallResult obj)
    public static WebCallResult CreateErrorResult(Error error)
}

有些 api 调用返回 CallResult,有些返回 WebCallResult。

现在我使用两次相同的代码来处理它:

// turn a webcall result into a Result object
let processResultWeb (applyOnOk: 'a -> 'b) (result: WebCallResult<'a>) =
    match result.Success with
    | true ->  Result.Ok (applyOnOk result.Data)
    | false -> Result.Error (decodeError result.Error)

// turn a webcall result into a Result object
let processResult (applyOnOk: 'a -> 'b) (result: CallResult<'a>) =
    match result.Success with
    | true ->  Result.Ok (applyOnOk result.Data)
    | false -> Result.Error (decodeError result.Error)

这并没有什么意义,因为它是相同的代码,我只关心来自基类 (CallResult) 的数据。

所以我想将这两种类型都转换为基类:

let a: WebCallResult = ...
let r = a :> CallResult

但这会导致编译器错误:

[FS0001] 'CallResult' 类型与'WebCallResult' 类型不兼容

我怎样才能通过仅访问其基类中的字段但使用相同的泛型类型来检查这两种类型的结果。

编辑: 类的源代码在这里:https://pastebin.com/mrw5W7xk

问题是我想从:

WebCallResult<'a'> to CallResult<'a>

而泛型似乎是个问题。

【问题讨论】:

  • 我觉得有些不对劲。如果WebCallResult&lt;T&gt; 是从CallResult 派生的,那么您应该可以毫无问题地从派生类转换为基类。
  • 这也是我的想法;我想知道这个问题是否是通用的;我在问题中添加了一个包含整个来源的链接。
  • 尝试转换为CallResult&lt;_&gt;,然后再转换为CallResult。我在想,既然涉及到泛型,也许分两步就可以了,但这只是一个想法。

标签: f#


【解决方案1】:

使用您的代码,即使使用泛型,我也可以毫无问题地进行转换。这是一个例子:

let foo x =
    WebCallResult<_>(System.Nullable(), Array.empty, x, Error())

let a : WebCallResult<int> = foo 3
let r = a :> CallResult<_>

let b : WebCallResult<string> = foo "str"
let q = b :> CallResult<_>

【讨论】:

  • 我这边缺少的部分是 <_>,我没有包括那个
  • 啊,我明白了。那么我对 Q 的评论也无关紧要。
猜你喜欢
  • 2015-05-29
  • 2011-07-15
  • 1970-01-01
  • 1970-01-01
  • 2015-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-23
相关资源
最近更新 更多