Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Net7 #13

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open

Net7 #13

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
dotnet-version: 7.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
4 changes: 2 additions & 2 deletions CSharpTypes/CSharpTypes.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Saithe\Saithe.fsproj" />
</ItemGroup>
</Project>
</Project>
11 changes: 8 additions & 3 deletions CSharpTypes/OrderId.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using Newtonsoft.Json;
using Saithe;
using System;
using System.Diagnostics.CodeAnalysis;

namespace CSharpTypes
{
/// <summary>
/// Order identifier, simple wrapper around long value. Since it wraps long we need to use the JsonConverter
/// </summary>
[JsonConverter(typeof(ParseTypeJsonConverter<OrderId>))]
public struct OrderId : IEquatable<OrderId>
public struct OrderId : IEquatable<OrderId>, IParsable<OrderId>
{
public readonly long Value;

Expand All @@ -21,7 +22,7 @@

public bool Equals(OrderId other)
{
if (ReferenceEquals(null, other)) return false;

Check warning on line 25 in CSharpTypes/OrderId.cs

View workflow job for this annotation

GitHub Actions / build

Do not pass an argument with value type 'CSharpTypes.OrderId' to 'ReferenceEquals'. Due to value boxing, this call to 'ReferenceEquals' will always return 'false'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2013)

Check warning on line 25 in CSharpTypes/OrderId.cs

View workflow job for this annotation

GitHub Actions / build

Do not pass an argument with value type 'CSharpTypes.OrderId' to 'ReferenceEquals'. Due to value boxing, this call to 'ReferenceEquals' will always return 'false'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2013)
return Equals(Value, other.Value);
}
public override bool Equals(object obj)
Expand All @@ -38,7 +39,7 @@
{
return Value.ToString();
}
public static bool TryParse(string str, out OrderId result)
private static bool TryParse(string str, out OrderId result)
{
result = Empty;
if (string.IsNullOrEmpty(str))
Expand All @@ -53,12 +54,16 @@
}
return false;
}
public static OrderId Parse(string str)
private static OrderId Parse(string str)
{
OrderId res;
if (TryParse(str, out res))
return res;
throw new Exception("Could not parse product id");
}

public static OrderId Parse(string s, IFormatProvider provider) => Parse(s);

public static bool TryParse([NotNullWhen(true)] string s, IFormatProvider provider, [MaybeNullWhen(false)] out OrderId result) => TryParse(s, out result);
}
}
22 changes: 18 additions & 4 deletions CSharpTypes/ParseValueType.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Saithe;

namespace CSharpTypes
{
[TypeConverter(typeof(ParseTypeConverter<ParseValueType>))]
public class ParseValueType : IEquatable<ParseValueType>
public class ParseValueType : IEquatable<ParseValueType>, IParsable<ParseValueType>
{
public readonly string Value;

Expand All @@ -26,16 +27,29 @@ public static ParseValueType Parse(string value)
public override bool Equals(object obj)
{
return Value.Equals(obj as ParseValueType);
}
}
public override int GetHashCode()
{
return Value.GetHashCode();
}

public bool Equals(ParseValueType other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(null, other)) return false;
return Value.Equals(other.Value);
}

public static ParseValueType Parse(string s, IFormatProvider provider) => Parse(s);

public static bool TryParse([NotNullWhen(true)] string s, IFormatProvider provider, [MaybeNullWhen(false)] out ParseValueType result)
{
try{
result = Parse(s);
return true;
}catch(Exception){
result = default;
return false;
}
}
}
}
11 changes: 8 additions & 3 deletions CSharpTypes/ProductId.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Saithe;

namespace CSharpTypes
{
[TypeConverter(typeof(ParseTypeConverter<ProductId>))]
public struct ProductId: IEquatable<ProductId>
public struct ProductId: IEquatable<ProductId>, IParsable<ProductId>
{
public readonly long Value;

Expand All @@ -18,7 +19,7 @@

public bool Equals(ProductId other)
{
if (ReferenceEquals(null, other)) return false;

Check warning on line 22 in CSharpTypes/ProductId.cs

View workflow job for this annotation

GitHub Actions / build

Do not pass an argument with value type 'CSharpTypes.ProductId' to 'ReferenceEquals'. Due to value boxing, this call to 'ReferenceEquals' will always return 'false'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2013)

Check warning on line 22 in CSharpTypes/ProductId.cs

View workflow job for this annotation

GitHub Actions / build

Do not pass an argument with value type 'CSharpTypes.ProductId' to 'ReferenceEquals'. Due to value boxing, this call to 'ReferenceEquals' will always return 'false'. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2013)
return Equals(Value, other.Value);
}
public override bool Equals(object obj)
Expand All @@ -35,7 +36,7 @@
{
return $"ProductId/{Value}";
}
public static bool TryParse(string str, out ProductId result)
private static bool TryParse(string str, out ProductId result)
{
result = Empty;
if (string.IsNullOrEmpty(str))
Expand All @@ -53,12 +54,16 @@
}
return false;
}
public static ProductId Parse(string str)
private static ProductId Parse(string str)
{
ProductId res;
if (TryParse(str, out res))
return res;
throw new Exception("Could not parse product id");
}

public static ProductId Parse(string s, IFormatProvider provider) => Parse(s);

public static bool TryParse([NotNullWhen(true)] string s, IFormatProvider provider, [MaybeNullWhen(false)] out ProductId result) => TryParse(s, out result);
}
}
37 changes: 33 additions & 4 deletions MvcApp/Models.fs
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,58 @@ let parseId prefix str =
| None -> raise (FormatException str)

[<Struct>]
[<TypeConverter(typeof<ParseTypeConverter<CustomerId>>)>]
[<TypeConverter(typeof<CustomerId_T1>)>]
type CustomerId =
{ Value : Guid }
static member Default : CustomerId = { Value=Guid.Empty }
static member Parse(str : string) : CustomerId = { Value = parseId "c-" str }
override this.ToString() = sprintf "c-%s" (toStr this.Value)
interface IParsable<CustomerId> with
static member Parse(s:string, f:IFormatProvider) = CustomerId.Parse(s)
static member TryParse(s:string, f:IFormatProvider, result:byref<CustomerId>) =
try
result <- CustomerId.Parse(s)
true
with _ ->
result <- Unchecked.defaultof<_>
false
and private CustomerId_T1 = ParseTypeConverter<CustomerId>

[<Struct>]
[<TypeConverter(typeof<ParseTypeConverter<ProductId>>)>]
[<TypeConverter(typeof<ProductId_T1>)>]
type ProductId =
{ Value : Guid }
static member Default : ProductId = { Value=Guid.Empty }
static member Parse(str : string) : ProductId = { Value = parseId "p-" str }
override this.ToString() = sprintf "p-%s" (toStr this.Value)
interface IParsable<ProductId> with
static member Parse(s:string, f:IFormatProvider) = ProductId.Parse(s)
static member TryParse(s:string, f:IFormatProvider, result:byref<ProductId>) =
try
result <- ProductId.Parse(s)
true
with _ ->
result <- Unchecked.defaultof<_>
false
and private ProductId_T1 = ParseTypeConverter<ProductId>

[<Struct>]
[<TypeConverter(typeof<ParseTypeConverter<OrderId>>)>]
[<TypeConverter(typeof<OrderId_T1>)>]
type OrderId =
{ Value : Guid }
static member Default : OrderId = { Value=Guid.Empty }
static member Parse(str : string) : OrderId = { Value = parseId "o-" str }
override this.ToString() = sprintf "o-%s" (toStr this.Value)

interface IParsable<OrderId> with
static member Parse(s:string, f:IFormatProvider) = OrderId.Parse(s)
static member TryParse(s:string, f:IFormatProvider, result:byref<OrderId>) =
try
result <- OrderId.Parse(s)
true
with _ ->
result <- Unchecked.defaultof<_>
false
and private OrderId_T1 = ParseTypeConverter<OrderId>

type Customer = {Id:CustomerId; FirstName:string ; LastName:string; Version:int}

Expand Down
4 changes: 2 additions & 2 deletions MvcApp/MvcApp.fsproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="Models.fs" />
Expand All @@ -17,4 +17,4 @@
<ProjectReference Include="..\Saithe\Saithe.fsproj" />
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" />
</ItemGroup>
</Project>
</Project>
14 changes: 8 additions & 6 deletions Saithe/ParseTypeConverters.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ open System.ComponentModel
open System
open System.Reflection
open Newtonsoft.Json
module internal MethodInfos=
let matchParse (t:MethodInfo) = t.Name<>null && (t.Name.Equals("Parse") || t.Name.EndsWith(".Parse")) && t.GetParameters().Length = 2

type ParseTypeConverter<'T (*when 'T :> IParsable<'T>*) >() = //when 'T : (static member parse : string -> 'T)
type ParseTypeConverter<'T when 'T :> IParsable<'T> >() =
inherit TypeConverter()
let strT = typeof<string>
let t = typeof<'T>
let parse_method = t.GetTypeInfo().GetMethod("Parse")
let parse_method = t.GetMethods() |> Array.find MethodInfos.matchParse

let parse s =
try
box (parse_method.Invoke(null, [| s |]))
box (parse_method.Invoke(null, [| s; null |]))
with :? TargetInvocationException as e -> raise (e.GetBaseException())

override this.CanConvertFrom(context, sourceType) = (strT = sourceType || sourceType = t)
Expand All @@ -30,15 +32,15 @@ type ParseTypeConverter<'T (*when 'T :> IParsable<'T>*) >() = //when 'T : (stati
if destinationType = t then box (parse value)
else box (value.ToString())

type public ParseTypeJsonConverter<'T>() =
type public ParseTypeJsonConverter<'T when 'T :> IParsable<'T> >() =
inherit JsonConverter()
let t = typeof<'T>

let parse_method = t.GetTypeInfo().GetMethod("Parse")
let parse_method = t.GetMethods() |> Array.find MethodInfos.matchParse

let parse s =
try
box (parse_method.Invoke(null, [| s |]))
box (parse_method.Invoke(null, [| s ; null |]))
with :? TargetInvocationException as e -> raise (e.GetBaseException())

override this.CanConvert(objectType) = objectType = t
Expand Down
2 changes: 1 addition & 1 deletion Saithe/Saithe.fsproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<PackageId>Saithe</PackageId>
<Authors>wallymathieu</Authors>
<Company></Company>
Expand Down
17 changes: 14 additions & 3 deletions Tests/Handle_discriminated_union.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ open Newtonsoft.Json
open System.ComponentModel
open System.Globalization


[<TypeConverter(typeof<ParseTypeConverter<ParseValueType>>)>]
[<JsonConverter(typeof<ParseTypeJsonConverter<ParseValueType>>)>]
[<TypeConverter(typeof<ParseValueType_T1>)>]
[<JsonConverter(typeof<ParseValueType_T2>)>]
type ParseValueType =
| ValueType of string
| Empty
Expand All @@ -24,6 +23,18 @@ type ParseValueType =
match this with
| Empty -> ""
| ValueType value -> sprintf "P_%s" value
interface IParsable<ParseValueType> with
static member Parse(s:string, f:IFormatProvider) = ParseValueType.Parse(s)
static member TryParse(s:string, f:IFormatProvider, result:byref<ParseValueType>) =
try
result <- ParseValueType.Parse(s)
true
with _ ->
result <- Unchecked.defaultof<_>
false
and private ParseValueType_T1 = ParseTypeConverter<ParseValueType>
and private ParseValueType_T2 = ParseTypeJsonConverter<ParseValueType>


[<Serializable>]
[<CLIMutable>]
Expand Down
12 changes: 11 additions & 1 deletion Tests/Parse_fs_type.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ open Newtonsoft.Json
open System.ComponentModel
open System.Globalization

[<TypeConverter(typeof<ParseTypeConverter<ParseValueType>>)>]
[<TypeConverter(typeof<ParseValueType_T1>)>]
type ParseValueType={ Value:string }
with
static member Parse (str:string)=
Expand All @@ -15,6 +15,16 @@ with
| _ -> raise (FormatException str)
override this.ToString()=
sprintf "P_%s" this.Value
interface IParsable<ParseValueType> with
static member Parse(s:string, f:IFormatProvider) = ParseValueType.Parse(s)
static member TryParse(s:string, f:IFormatProvider, result:byref<ParseValueType>) =
try
result <- ParseValueType.Parse(s)
true
with _ ->
result <- Unchecked.defaultof<_>
false
and private ParseValueType_T1 = ParseTypeConverter<ParseValueType>

[<Serializable>]
[<CLIMutable>]
Expand Down
4 changes: 2 additions & 2 deletions Tests/Tests.fsproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<AssemblyName>Tests</AssemblyName>
<PackageId>Tests</PackageId>
</PropertyGroup>
Expand All @@ -27,4 +27,4 @@
<PackageReference Update="FSharp.Core" Version="6.0.5" />
<PackageReference Include="FsCheck.Xunit" Version="2.16.5" />
</ItemGroup>
</Project>
</Project>
2 changes: 2 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
image: Visual Studio 2022
install:
- cmd: choco install dotnetcore-sdk --pre -y

build_script:
- dotnet restore
Expand Down
5 changes: 3 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"sdk": {
"version": "6.0.0",
"rollForward": "latestFeature"
"version": "7.0.0",
"rollForward": "latestFeature",
"allowPrerelease": true
}
}
Loading