In my WPF project I have something like this:
open PropertyChanged
[<ImplementPropertyChanged>]
type Type1 =
{ mutable Name : string
mutable Value : decimal }
, and it works fine when compiled and application is running. But in F# interactive I see that "Type1" is not instance of IPropertyChanged. Is there any way to fix it?
Related
Say I have the following type defined:
type Foo = { A: string; B: int }
I want a function parse, such that:
let myfoo = parse<Foo> "{A = \"foo\"; B = 5}"
gives me an instance of type Foo (or error).
Is this possible using FSharp.Compiler.Service?
UPDATE:
While there are other questions that address parsing of F# code, they don't address having references in the current assembly.
You can do this by referencing the current assembly from the hosted F# interactive - this only works if you are running this from a compiled program (which has assembly located on disk) and if your types are public, but it may do the trick in your case.
Given the usual setup documented on the Embedding F# Interactive page, you can do something like this:
module Program
type Test = { A:int; B:string }
// (omitted code to initialize the fsi service)
let fsiSession = FsiEvaluationSession.Create(...)
// Run #r command to reference the current assembly
let loc = System.Reflection.Assembly.GetExecutingAssembly().Location
fsiSession.EvalInteraction(sprintf "#r #\"%s\"" loc)
// Open the module or namespace containing your types
fsiSession.EvalInteraction("open Program")
// Evaluate code using the type and cast it back to our type
let value = fsiSession.EvalExpression("{A=0; B=\"hi\"}").Value.ReflectionValue :?> Test
printfn "%A" value
I'm using Entity Framework Core 2.1 in F#.
I want to setup a generic type conversion for Option types so that EF knows how to handle them.
I found this very helpful post that shows how to setup a generic convertor for Option types.
So here's what I have so far (putting snippits together)
[<Table("Users", Schema = "pm")>]
type [<CLIMutable>] User = {
[<DatabaseGenerated(DatabaseGeneratedOption.Identity)>]
UserID : int64
FirstName : string
LastName : string
LastLoggedInTime : DateTimeOffset option
}
with
static member Configure (mb : ModelBuilder) =
mb.Entity<User>()
.Property(fun p -> p.LastLoggedInTime)
.HasConversion(OptionConverter<DateTimeOffset>()) |> ignore
This is great, except if I add a new property to my type. I will need to add the last three lines of the above code for that property as well. I'm looking for a way to do it for all properties all at once :D
So then I found this helpful SO answer that lead me to the below code
let tt = mb.Model.GetEntityTypes()
|> Seq.map(fun et -> et.GetProperties()) |> Seq.concat
|> Seq.filter(fun p -> p.ClrType = typeof<Option<DateTimeOffset>>)
|> Seq.map(fun p -> mb.Entity(p.DeclaringEntityType.ClrType)
.Property(p.Name)
.HasConversion(OptionConverter<DateTimeOffset>()))
Now the problem that I'm trying to solve is to figure out how to make this code work with Generic types so I don't have to specify the type. I want it to be something like p.ClrType = typeof<Option<T'>> and at the end, something like .HasConversion(OptionConverter<T'>())
Any thoughts?
so going off your initial question "I want to setup a generic type conversion for Option types so that EF knows how to handle them." I am assuming you mean you want EF to properly map an option to a "NULL" column of the corresponding base type, and that you are having problems because EF doesn't know how to handle FSharp.Option?
You could instead just use Nullable in place of Option for your EF types, and it will resolve as it does in C#.
So for instance, your example type becomes:
type [<CLIMutable>] User = {
[<DatabaseGenerated(DatabaseGeneratedOption.Identity)>]
UserID : int64
FirstName : string
LastName : string
LastLoggedInTime : Nullable<DateTimeOffset>
}
For types that can not be Nullable but are Options in your domain (strings for example), you just set them as their base type and it will work just fine.
If you are mapping to F# domain types somewhere else, you can just use Option.ToNullable and Option.OfNullable there, or map None to null if the type cannot be nullable as stated above.
Hope this helps!
I have the following code:
open NSubstitute
type MyClass()=
let myObject = Substitute.For<IMyInterface>()
do myObject.MyProperty.Returns(true)
do myObject.MyMethod().Returns(true)
On "Returns" (both) I get the error that is not defined. The equivalent C# code works without issue. Adding |> ignore at the end of the do lines does not help. Am I missing something there?
I know you wrote that adding |> ignore at the end doesn't help, but this compiles on my machine:
type IMyInterface =
abstract MyProperty : bool with get, set
abstract member MyMethod : unit -> bool
open NSubstitute
type MyClass() =
let myObject = Substitute.For<IMyInterface>()
do myObject.MyProperty.Returns(true) |> ignore
do myObject.MyMethod().Returns(true) |> ignore
I attempted to infer the definition of IMyInterface from the question; did I get it wrong?
So after I tried the code (Mark Seemann's, as to avoid my C# class) on VS2012, fsi, through direct compilation with fsc and on VS2013, the issue is clearly a VS2012 problem. The code works correctly with the other three.
Not sure yet if it is using a different version of F#. Will need further investigation. But at least, for now, on VS2012 I can use:
do SubstituteExtensions.Returns(myObject.MyProperty, true) |> ignore
It works as well when I need to pass parameters to methods.
Updated below...
I recently started experimenting with ServiceStack in F#, so naturally I started with porting the Hello World sample:
open ServiceStack.ServiceHost
open ServiceStack.ServiceInterface
open ServiceStack.WebHost.Endpoints
[<CLIMutable; Route("/hello"); Route("/hello/{Name}")>]
type Hello = { Name : string }
[<CLIMutable>]
type HelloResponse = { Result : string }
type HelloService() =
inherit Service()
member x.Any(req:Hello) =
box { Result = sprintf "Hello, %s!" req.Name }
type HelloAppHost() =
inherit AppHostBase("Hello Web Services", typeof<HelloService>.Assembly)
override x.Configure container = ()
type Global() =
inherit System.Web.HttpApplication()
member x.Application_Start() =
let appHost = new HelloAppHost()
appHost.Init()
That works great. It's very concise, easy to work with, I love it. However, I noticed that the routes defined in the sample allow for the Name parameter to not be included. Of course, Hello, ! looks kind of lame as output. I could use String.IsNullOrEmpty, but it is idiomatic in F# to be explicit about things that are optional by using the Option type. So I modified my Hello type accordingly to see what would happen:
[<CLIMutable; Route("/hello"); Route("/hello/{Name}")>]
type Hello = { Name : string option }
As soon as I did this, the F# type system forced me to deal with the fact that Name might not have a value, so I changed HelloService to this to get everything to compile:
type HelloService() =
inherit Service()
member x.Any(req:Hello) =
box { Result =
match req.Name with
| Some name -> sprintf "Hello, %s!" name
| None -> "Hello!" }
This compiles, and runs perfectly when I don't supply a Name parameter. However, when I do supply a name...
KeyValueDataContractDeserializer: Error converting to type: Type
definitions should start with a '{', expecting serialized type
'FSharpOption`1', got string starting with: World
This wasn't a complete surprise of course, but it brings me to my question:
It would be trivial for me to write a function that can wrap an instance of type T into an instance of type FSharpOption<T>. Are there any hooks in ServiceStack that would let me provide such a function for use during deserialization? I looked, but I couldn't find any, and I'm hoping I was just looking in the wrong place.
This is more important for F# use than it might seem at first, because classes defined in F# are by default not allowed to be null. So the only (satisfying, non-hacky) way of having one class as an optional property of another class is with, you guessed it, the Option type.
Update:
I was able to sort-of get this working by making the following changes:
In the ServiceStack source, I made this type public:
ServiceStack.Text.Common.ParseFactoryDelegate
...and I also made this field public:
ServiceStack.Text.Jsv.JsvReader.ParseFnCache
With those two things public, I was able to write this code in F# to modify the ParseFnCache dictionary. I had to run this code prior to creating an instance of my AppHost - it didn't work if I ran it inside the AppHost's Configure method.
JsvReader.ParseFnCache.[typeof<Option<string>>] <-
ParseFactoryDelegate(fun () ->
ParseStringDelegate(fun s -> (if String.IsNullOrEmpty s then None else Some s) |> box))
This works for my original test case, but aside from the fact that I had to make brittle changes to the internals of ServiceStack, it sucks because I have to do it once for each type I want to be able to wrap in an Option<T>.
What would be better is if I could do this in a generic way. In C# terms, it would be awesome if I could provide to ServiceStack a Func<T, Option<T>> and ServiceStack would, when deserializing a property whose generic type definition matches that of the return type of my function, deserialize T and then pass the result into my function.
Something like that would be amazingly convenient, but I could live with the once-per-wrapped-type approach if it were actually part of ServiceStack and not my ugly hack that probably breaks something somewhere else.
So there are a couple of extensibility points in ServiceStack, on the framework level you can add your own Custom Request Binder this allows you to provide your own model binder that's used, e.g:
base.RequestBinders.Add(typeof(Hello), httpReq => {
var requestDto = ...;
return requestDto;
});
But then you would need to handle the model binding for the different Content-Types yourself, see CreateContentTypeRequest for how ServiceStack does it.
Then there are hooks at the JSON Serializer level, e.g:
JsConfig<Hello>.OnDeserializedFn = dto => newDto;
This lets you modify the instance of the type returned, but it still needs to be the same type but it looks like the F# option modifier changes the structural definition of the type?
But I'm open to adding any hooks that would make ServiceStack more palatable for F#.
What does the code look like to generically convert a normal Hello type to an F# Hello type with option?
The only thing I can think of is to replace the option type with your own type, one that has an implicit conversion from string to myOption, and anything else you need.
Not all that nice, but workable. Your type would probably also need to be serializable.
type myOption =
| None
| Some of string
static member public op_Implicit (s:string) = if s <> null then Some s else None
member public this.Value = match this with
| Some s -> s
| _ -> null
member this.Opt = match this with
| Some s -> Option.Some s
| None -> Option.None
Your record type would then be
[<CLIMutable>]
type Hello =
{ Name : myOption }
On the other hand, ServiceStack is open source, so maybe something could be done there.
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
}