If I have a C# 9 record defined:
public record Reading
{
public long Timestamp { get; init; }
public float TemperatureCelsius { get; init; }
}
How do I instantiate it from F# (5.01)?
let newReading () =
// ???
It feels like it should be simple, but I can't seem to get it to work.
I created two projects, both using .NET Core 5.0:
CSharpProj: C# 9 class library
FSharpProj: F# 5 console app
Instantiating the C# record from F# works fine for me, if I treat it like a normal class type:
open CSharpProj
let reading = Reading()
However, I'm unable to successfully set either Timestamp or TemperatureCelsius from F#. It looks like F# doesn't understand C# init setters yet. The following attempt compiles fine:
let reading = Reading(Timestamp = 1L, TemperatureCelsius = 1.0f)
But generates an InvalidProgramException at runtime. I assume the F# team will address this problem at some point. In the meantime, as a work-around, I changed the C# record type to:
public record Reading(long Timestamp, float TemperatureCelsius)
{
}
And now the same invocation from F# successfully sets the two properties.
Related
I am using a third party API that rather clumsily makes use of ref parameters to produce outputs. Personally I really hate this design of an API but it's what I have available to me right now. I've had to hide the datatypes of the API slightly due to proprietary code but this should be irrelevant to the problem at hand.
Anyway in C# I can pass a null reference as a ref parameter successfully as follows:
IDataType tl = null;
bool success = api.myFunction(ref tl);
However in F# the following will not work
let mutable tl : IDataType = null //null reference assignment in F#
let success = api.myFunction(&tl) //& means ref in F#
It returns a null reference exception error. No such error is returned in C#.
Has anyone experiences this before? I am thinking it must be a bug in the API itself which is relatively ancient design.
**Edit: This should be closed, I believe the answer does not lie in the F# code but in the API as it's already a number of known bugs similar to this.
Quick and dirty prototyping of your API in C#
namespace API
{
public interface IDataType { void Hi(); }
public class API: IDataType {
public void Hi() { System.Console.WriteLine("Hi!"); }
public bool MyFunction(ref IDataType iface) {
iface = new API();
return true;
}
}
}
and then using it from F# exactly your way while staying within the same CLR:
let mutable iface : API.IDataType = null
if API.API().MyFunction(&iface) then iface.Hi()
works without any problem.
So, indeed, your problem is specific to your given API and has nothing to do with the form of its use from F#.
Using a ref cell is also an option here. Does this work?
let tl = ref null
let success = api.myFunction(tl)
The problem was with the API being compiled in .NET 2.0 which works fine under C# but not F#.
I'm testing a bit redis using .Net, I've read this tutorial
http://www.d80.co.uk/post/2011/05/12/Redis-Tutorial-with-ServiceStackRedis.aspx
and follow using c# and worked perfect, now when I'm trying translate this to f# I've a weird behavior, first I create a simple f# class (using type didn't work neither but it was expected)...basicaly the class is something like this:
//I ve used [<Class>] to
type Video (id : int, title : string , image : string , url : string) =
member this.Id = id
member this.Title = title
member this.Image = image
member this.Url = url
when I run the code, my db save an empty data, if I use a c# class inside my f# code this work, so I'm sure than the problem is the f# class...How can resolve this without depend c# code inside my f# code
Thanks !!!
Based on your tutorial, it looks like you want your F# Video class to be full of getter and setter properties instead of having a constructor with getters only as it is now (and it is a class, which you can verify by running it through FSI).
You can achieve this using a record type full of mutable fields (which is compiled down to a class type full of public getters and setters):
type Video = {
mutable Id : int
mutable Title : string
mutable Image : byte[]
mutable Url : string
}
I am trying to convert this C# code to F#:
double[,] matrix;
public Matrix(int rows, int cols)
{
this.matrix = new double[rows, cols];
}
public double this[int row, int col]
{
get
{
return this.matrix[row, col];
}
set
{
this.matrix[row, col] = value;
}
}
Basically my biggest problem is creating the indexer in F#. I couldn't find anything that I could apply in this situation anywhere on the web. I included a couple of other parts of the class in case incorporating the indexer into a Matrix type isn't obvious. So a good answer would include how to make a complete type out of the three pieces here, plus anything else that may be needed. Also, I am aware of the matrix type in the F# powerpack, however I am trying to learn F# by converting C# projects I understand into F#.
Thanks in advance,
Bob
F# calls them "indexed properties"; here is the MSDN page. In F# they work slightly differently - each indexed property has a name.
However, there is a default one called "Item". So an implementation of your example would look like this:
member this.Item
with get(x,y) = matrix.[(x,y)]
and set(x,y) value = matrix.[(x,y)] <- value
Then this is accessed via instance.[0,0]. If you have named it something other than "Item", you would access it with instance.Something[0,0].
I'm working on a biztalk project and use a map to create the new message.
Now i want to map a datefield to a string.
I thought i can do it on this way with an Function Script with inline C#
public string convertDateTime(DateTime param)
{
return System.Xml.XmlConvert.ToString(param,ÿyyyMMdd");
}
But this doesn't work and i receive an error. How can i do the convert in the map?
It's a Biztalk 2006 project.
Without the details of the error you are seeing it is hard to be sure but I'm quite sure that your map is failing because all the parameters within the BizTalk XSLT engine are passed as strings1.
When I try to run something like the function you provided as inline C# I get the following error:
Object of type 'System.String' cannot be converted to type 'System.DateTime'
Replace your inline C# with something like the following:
public string ConvertDateTime(string param1)
{
DateTime inputDate = DateTime.Parse(param1);
return inputDate.ToString("yyyyMMdd");
}
Note that the parameter type is now string, and you can then convert that to a DateTime and perform your string format.
As other answers have suggested, it may be better to put this helper method into an external class - that way you can get your code under test to deal with edge cases, and you also get some reuse.
1 The fact that all parameters in the BizTalk XSLT are strings can be the source of a lot of gotchas - one other common one is with math calculations. If you return numeric values from your scripting functoids BizTalk will helpfully convert them to strings to map them to the outbound schema but will not so helpfully perform some very random rounding on the resulting values. Converting the return values to strings yourself within the C# will remove this risk and give you the expected results.
If you're using the mapper, you just need a Scripting Functiod (yes, using inline C#) and you should be able to do:
public string convertDateTime(DateTime param)
{
return(param.ToString("YYYYMMdd");
}
As far as I know, you don't need to call the System.Xml namespace in anyway.
I'd suggest
public static string DateToString(DateTime dateValue)
{
return String.Format("{0:yyyyMMdd}", dateValue);
}
You could also create a external Lib which would provide more flexibility and reusability:
public static string DateToString(DateTime dateValue, string formatPicture)
{
string format = formatPicture;
if (IsNullOrEmptyString(formatPicture)
{
format = "{0:yyyyMMdd}";
}
return String.Format(format, dateValue);
}
public static string DateToString(DateTime dateValue)
{
return DateToString(dateValue, null);
}
I tend to move every function I use twice inside an inline script into an external lib. Iit will give you well tested code for all edge cases your data may provide because it's eays to create tests for these external lib functions whereas it's hard to do good testing on inline scripts in maps.
This blog will solve your problem.
http://biztalkorchestration.blogspot.in/2014/07/convert-datetime-format-to-string-in.html?view=sidebar
Regards,
AboorvaRaja
Bangalore
+918123339872
Given that maps in BizTalk are implemented as XSL stylesheets, when passing data into a msxsl scripting function, note that the data will be one of types in the Equivalent .NET Framework Class (Types) from this table here. You'll note that System.DateTime isn't on the list.
For parsing of xs:dateTimes, I've generally obtained the /text() node and then parse the parameter from System.String:
<CreateDate>
<xsl:value-of select="userCSharp:GetDateyyyyMMdd(string(s0:StatusIdChangeDate/text()))" />
</CreateDate>
And then the C# script
<msxsl:script language="C#" implements-prefix="userCSharp">
<![CDATA[
public System.String GetDateyyyyMMdd(System.String p_DateTime)
{
return System.DateTime.Parse(p_DateTime).ToString("yyyyMMdd");
}
]]>
I'm getting a strange error when I use F# to read a public readonly member of a struct type defined in a C# assembly.
// C#: compile to Lib.dll
namespace Lib
{
public class MyClass { public readonly int ReadonlyFoo; }
public struct MyStruct
{
public readonly int ReadonlyFoo;
public int WriteableFoo;
}
}
// F#: compile to Client.exe
open Lib
let myClass = new MyClass()
printfn "MyClass.ReadonlyFoo = %x" myClass.ReadonlyFoo
let myStruct = new MyStruct()
printfn "MyStruct.WriteableFoo = %x" myStruct.WriteableFoo
printfn "MyStruct.ReadonlyFoo = %x" myStruct.ReadonlyFoo
When I compile Client.exe with F# 1.9.6.16, the last line gives the error:
"The address of the variable 'copyOfStruct' may not be used at this point"
The web is useless as of the time of this writing. It seems odd that one can read an immutable member of a class, and one can read a mutable member of a struct, but one can't read an immutable member of a struct. A workaround is easy enough, but I'm curious: is this a bug in the compiler?
Edit: I submitted a bug report to fsbugs#microsoft.com
Normally when people say 'it looks like a bug in the compiler' that is code for 'I don't know what I'm doing'. In this situation however, it does look to be like a bug.
The F# compiler makes a copy of structs behind the scenes in case they get mutated. (This is why even if you define a struct with mutable fields you must attribute the instance of that struct as mutable before you can update its fields.) It appears that the special magic going on behind the scenes forgets about 'readonly' struct fields.
While the internet and StackOverflow are a great place to ask for help about F#-related issues, please do let the F# team know about any bugs you find by emailing fsbugs#microsoft.com.