简体   繁体   中英

F# 4.5.0.0: error FS0193: This expression is a function value, i.e. is missing arguments. Its type is Exception -> 'a

I'm adapting a class from C# to F#, in the code I have a method that throws an exception and this method needs to have a generic return. When in C# to F# it works perfectly, but from F# to F# a compilation error happens: FS0193 This expression is a function value, ie is missing arguments. Its type is Exception -> 'a.

        member this.Throw() =
            try
               raise ...
            with
            | exc -> ...
            Unchecked.defaultof<'T> // <- Error

If the complete type is needed, I edit the question.

Ok Gus. Edit: My goal is to port FSharp.Core version 4.5.0.0 to .NET 4.0. To achieve my goal I am rewriting parts of Theraot.Core in F#, since FSharp.Core does not "accept" third party libraries: https://github.com/theraot/Theraot/issues/121 .

Class in C#: https://github.com/theraot/Theraot/blob/master/Framework.Core/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs

Type in F#:

namespace System.Runtime.ExceptionServices

open System
open Microsoft.FSharp.Core
open System.Text
open System.Reflection

/// <summary>
///     The ExceptionDispatchInfo object stores the stack trace information and Watson information that the exception
///     contains at the point where it is captured. The exception can be thrown at another time and possibly on another
///     thread by calling the ExceptionDispatchInfo.Throw method. The exception is thrown as if it had flowed from the
///     point where it was captured to the point where the Throw method is called.
/// </summary>
[<Sealed;AllowNullLiteral>]
type ExceptionDispatchInfo private(exc : exn) =

    let _stackTrace = exc.StackTrace
    static member val private _remoteStackTraceString : FieldInfo = null with get, set

    /// <summary>
    ///     Gets the exception that is represented by the current instance.
    /// </summary>
    member val SourceException = exc with get

    /// <summary>
    ///     Creates an ExceptionDispatchInfo object that represents the specified exception at the current point in code.
    /// </summary>
    /// <param name="source">The exception whose state is captured, and which is represented by the returned object.</param>
    /// <returns>An object that represents the specified exception at the current point in code. </returns>
    static member Capture(source : exn) =
        if source = null
            then raise(new ArgumentNullException "source")
        new ExceptionDispatchInfo(source)

    /// <summary>
    ///     Throws the exception that is represented by the current ExceptionDispatchInfo object, after restoring the state
    ///     that was saved when the exception was captured.
    /// </summary>
    member this.Throw() =
        try
            raise this.SourceException
        with
        | exc ->
            let newStackTrace = _stackTrace + ExceptionDispatchInfo.BuildStackTrace(Environment.StackTrace)
            ExceptionDispatchInfo.SetStackTrace(this.SourceException, newStackTrace)
            raise

    static member private BuildStackTrace(trace : string) =
        let items = trace.Split([|Environment.NewLine|], StringSplitOptions.RemoveEmptyEntries)
        let newStackTrace = new StringBuilder()
        let mutable found = false
        let mutable contains = false
        for item in items do
            if not contains then
                if item.Contains ":" then
                    if item.Contains "System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"
                        then contains <- true
                    else
                        if found
                            then newStackTrace.Append Environment.NewLine |> ignore
                        found <- true
                        newStackTrace.Append item |> ignore
                elif found
                    then contains <- true
        newStackTrace.ToString()

    static member private GetFieldInfo() =
        if ExceptionDispatchInfo._remoteStackTraceString = null then
            // ---
            // Code by Miguel de Icaza
            let mutable remoteStackTraceString = typeof<Exception>.GetField("_remoteStackTraceString", BindingFlags.Instance ||| BindingFlags.NonPublic)
            if remoteStackTraceString = null then remoteStackTraceString <- typeof<Exception>.GetField("remote_stack_trace", BindingFlags.Instance ||| BindingFlags.NonPublic)
            ExceptionDispatchInfo._remoteStackTraceString <- remoteStackTraceString
        ExceptionDispatchInfo._remoteStackTraceString

    static member private SetStackTrace(exc : exn, value) =
        let remoteStackTraceString = ExceptionDispatchInfo.GetFieldInfo()
        remoteStackTraceString.SetValue(exc, value)

Where the error occurs: https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/async.fs#L65

If Gus needs more information or screenshots, just comment.

The problem is that you translated C# throw; as just raise - but this is not correct. If you want to re-throw the current exception, you need to use the reraise() function:

member this.Throw() =
    try
        raise this.SourceException
    with
    | exc ->
        let newStackTrace = _stackTrace + 
            ExceptionDispatchInfo.BuildStackTrace(Environment.StackTrace)
        ExceptionDispatchInfo.SetStackTrace(this.SourceException, newStackTrace)
        reraise()

What happens in your orginal code is that the Throw() method does not return a value, but instead returns the value of the raise function, which is a function that throws a given exception. This is syntactically valid, but has a differnt type than you expect.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM