Mocking NLog4Net with NSubstitute and capturing parameters passed to log.ErrorFormat - f#

Am trying to rewrite into F# the following C# which mocks up a Log4Net logger with NSubstitute and captures the parameters passed to a Log.ErrorFormat call into the _loggerException string.
string _loggerException = string.Empty;
this.c_logger.When(log => log.ErrorFormat(
Arg.Any<string>(), Arg.Any<string>()))
.Do(logger => _loggerException = logger.Arg<string>().ToString());
The following is the F# I have reached
let mutable _loggerException = System.String.Empty
let _logger = Substitute.For<ILog>()
SubstituteExtensions.When(_logger, _logger.WarnFormat(Arg.Any<string>(), Arg.Any<string>())).Do(fun logger -> _loggerException <- logger.Arg<string>())
However I am getting an error on the second parameter to SubstituteExtensions.When - _logger.WarnFormat(Arg.Any<string>(), Arg.Any<string>()) as follows:
This expression was expected to have type Action<ILog> but here has type unit.
Any thoughts on what I am doing wrong?

Related

execute c# method with multiple parameters from f#

I am new to F#, and I am trying to execute a static C# function that accepts multiple parameters from the F# file/code.
I have a single solution which contains both, C# project as well as F# project.
C# project
Code from the C# file:
using ...
namespace Factories
{
public static class FruitFactory
{
public static string GiveMe(int count, string fruitname)
{
...
...
return ... (string) ...
}
}
}
F# project
Code from the F# file:
open System
open Factories
[<EntryPoint>]
let main argv =
let result = FruitFactory.GiveMe 2 "Apples"
printfn "%s" result
printfn "Closing Fruit Factory!"
0
From the above piece of code, I am getting the below errors for the code let result = FruitFactory.GiveMe 2 "Apples"
Error 1:
Program.fs(6, 37): [FS0001] This expression was expected to have type
'int * string'
but here has type
'int'
Error 2:
Program.fs(6, 18): [FS0003] This value is not a function and cannot be applied.
C# functions are uncurried, so you have to call it as though it takes a tuple, like this: FruitFactory.GiveMe(2, "Apples").
If you really want to create a C# function that can be called with curried arguments from F#, you have process each argument separately. It's not pretty, but it can be done like this:
C# project
using Microsoft.FSharp.Core;
public static class FruitFactory
{
/// <summary>
/// Curried version takes the first argument and returns a lambda
/// that takes the second argument and returns the result.
/// </summary>
public static FSharpFunc<string, string> GiveMe(int count)
{
return FuncConvert.FromFunc(
(string fruitname) => $"{count} {fruitname}s");
}
}
F# project
You can then call it the way you want from F#:
let result = FruitFactory.GiveMe 2 "Apple"
printfn "%s" result
Multiparameter .NET methods show up in F# as methods with tupled parameters:
let result = FruitFactory.GiveMe(2, "Apples")

F# - Use C# methods with out parameter (within arrays and void return)

I've read the-f-equivalent-of-cs-out but still I can't make it work for my case (the simplest solution/syntax).
I have this method in a C# project:
//<Project Sdk="Microsoft.NET.Sdk">
//<TargetFrameworks>netcoreapp3.1;netstandard2.0</TargetFrameworks>
public static void ABC(out byte[] a, out byte[] b, byte[] c)
{
var aaa = new byte[10];
var bbb = new byte[10];
a = aaa;
b = bbb;
}
Now, I want to use it in a F# project:
I'm using FSharp.Core 4.7.2
(* <Project Sdk="Microsoft.NET.Sdk">
<TargetFrameworks>netcoreapp3.1;netstandard2.0</TargetFrameworks> *)
let a,b = ABC(c)
I'm imitating the syntax of TryParse and this compiles without errors:
let success, number = System.Int32.TryParse("0")
The compiler on my ABC(c) call complains about the fact the signature asks for 3 parameters, not 1.
Compared to the TryParse I see 2 differences:
It does not return void
It uses Array objects
The compiler accepts this syntax:
let a = Array.empty<byte>
let b = Array.empty<byte>
ABC(ref a, ref b, c)
but:
I think it is not correct to use ref here, not in this way (because a and b are not mutable)
I'd like to use the clean syntax similar to TryParse and I WANT to know why it does not work here
I can change the C# project code, but replacing all the out parameters in that proejct will be a second step and maybe a new qeustion if I have difficulties or doubt.
[Update: parameter position]
I played a little with this and seems like I found when the "simple" syntax (without passing ref parameters) is broken.
public static void TryParseArray(string input, out int[] result) {
result = new int[0];
}
public static void TryParseArray_2(out int[] result, string input) {
result = new int[0];
}
let arr = csharp.TryParseArray("a") // OK
let arr = csharp.TryParseArray_2("a") // ERROR
It seems like the out parameter must be at the end (= not followed by normal parameters) in the C# methods, to make possible for F# to use them as returned tuple.
You correctly noticed that the "simplified" F# syntax for turning out parameters into returned tuples only works in very limited situations - only when you have one parameter and it is the last one. In other words, this feature helps with some common patterns, but it does not fully replace out parameters.
If you want to use out parameter in F#, you can either pass a reference to a local mutable variable using the &var syntax, or you can specify a reference cell of type int ref as an argument. The following shows the two options using the standard TryParse method:
// Using a local mutable variable
let mutable n = 0
Int32.TryParse("42", &n)
printfn "Got: %d" n
// Using a reference cell initialized to 0
let n = ref 0
Int32.TryParse("42", n)
printfn "Got: %d" n.Value

Why can an argument for the ICommand.Execute method be ignored?

Why is an argument not required for the following statement?
viewModel.Submit.Execute()
Is the argument an implicit unit type?
The signature for ICommand.Execute is the following:
/// <summary>
/// Defines the method that should be executed when the command is executed.
/// </summary>
/// <param name="parameter">A parameter that may be used in executing the command. This parameter may be ignored by some implementations.</param>
void Execute(object parameter);
Note the last comment on the summary:
This parameter may be ignored by some implementations.
The following DelegateCommand implementation is as follows:
module UILogic.Interaction
open System
open System.Windows
open System.Windows.Input
open System.ComponentModel
type DelegateCommand (action:(obj -> unit), canExecute:(obj -> bool)) =
let event = new DelegateEvent<EventHandler>()
interface ICommand with
[<CLIEvent>]
member this.CanExecuteChanged = event.Publish
member this.CanExecute arg = canExecute(arg)
member this.Execute arg = action(arg)
The client to this command is as follows:
// Setup
let viewModel = ViewModel()
viewModel.FirstName <- "Scott"
viewModel.LastName <- "Nimrod"
// Test
viewModel.Submit.Execute()
In conclusion, I just don't understand how an argument NOT marked optional can still be ignored in F#.
Any explanation on why this can occur?
() is a value in (of type unit) in F# too ... it will be translated into null
you can try this if you want:
> ();;
val it : unit = ()
> box ();;
val it : obj
= null

define a F# function and avoid the return value

define a function that has a single parameter of type string which which displayed on console. invoke the function passing it a message. ensure the function ignores any returned value
open System
let NoReturnFunction msg =
Console.WriteLine(string(msg))
NoReturnFunction "Hello World"
I am in a trouble to how to avoid return value of function
In this case there is no work to do because the WriteLine method doesn't return any values. It's a void returning function. In general though the way to ignore a return value in F# is to use the ignore function.
1 + 2 |> ignore
Couple of minor nit picks on the your code sample. The first is you can avoid the cast to string by simply typing the parameter. Second in F# it's more idiomatic to use the printfn function instead of Console.WriteLine
let NoReturnFunction (msg : string) =
printfn "%s" msg
For sake of completeness, you can also let F# infer the parameter type and the return type--like so:
let NoReturnFunction st = printfn "%s" st
This infers the type of s and the return type of NoReturnFunction (unit in this case).

Multiple parameters to methods in F#

I've got a class written in F# that I'm consuming in C#, that defines a method Render:
member this.Render template (context: IContext) =
let tokens = Lexer.tokenize template
let parser = new DefaultParser([for filter in _filters -> filter])
let resp = new StringBuilder()
for node in parser.Parse tokens None do
ignore <| resp.Append(node.render context)
resp.ToString()
The signature of this method is template:string -> (IContext -> string), which of course reads as "member Render takes a string parameter, then returns a function that takes an IContext and produces a string.
If I change the declaration from "member" to a let binding, defining it as a function local to the class definition:
let Render template (context: IContext) = ...
Then the signature becomes what you would expect it to be - string -> IContext -> string, which reads "Render takes a string, then an IContext and produces a string".
Is there a way to make a member behave like the let binding? This is causing issues consuming this member from C#, as the signature becomes Render(string, FastFunc<IContext, string>), which is not overly usable.
If you want to expose to C#, you should write it tupled style:
> type Foo =
- member this.Bar (param1, param2) = param1 + param2;;
type Foo =
class
member Bar : param1:int * param2:int -> int
end
That'll expose a normal .NET style method.

Resources