如何建立符合业务规则的F#类型? [英] How to build F# type fulfilling business rules?

查看:99
本文介绍了如何建立符合业务规则的F#类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在F#中建立一个类型,当我得到该类型的对象时,可以确保它处于有效状态.
该类型称为JobId,它仅包含一个Guid.
业务规则是:它必须是Guid,但不能为空Guid.
我已经在C#中实现了该类型,但是现在我想将其移植到F#类库中.

I´m trying to build a type in F#, where when I get an object of that type I can be sure it´s in a valid state.
The type is called JobId and it just holds a Guid.
The business rule is: It must be a Guid - but no empty Guid.
I´ve already implemented the type in C# but now I would like to port it to a F# class library.

这是C#类型:

public sealed class JobId
{
    public string Value { get; }

    private JobId(string value)
        => Value = value;

    public static JobId Create()
        => new JobId(Guid.NewGuid().ToString("N"));

    public static Option<JobId> Create(Guid id)
        => id == Guid.Empty
        ? None
        : Some(new JobId(id.ToString("N"));

    public static Option<JobId> Create(string id)
    {
        try
        {
            var guid = new Guid(id);
            return Create(guid);
        }
        catch (FormatException)
        {
            return None;
        }
    }
}

那么我该如何在F#中构建它?谢谢!

So how do I build that in F#? Thanks!

更新1:
我试图将其实现为可区分的联合类型,如下所示:

Update 1:
I tried to implement it as discriminated union type like this:

type JobId =
    | JobId of string

但是问题是,我无法用这种方法定义任何业务规则.
因此,最后一个问题是:如何确保JobId中的string 特定格式?

But the problem is, that I can´t define any business rules with that approach.
So the final question is: How to ensure that the string in JobId ist in a certain format?

推荐答案

区分的联合和F#记录使内部表示形式公开,因此仅在内部表示形式的所有值均有效的情况下才有效.如果需要定义进行一些检查的基本类型,则需要隐藏其内部的类型.在这种情况下,我将直接使用与您的C#代码相当的F#等效语言:

Discriminated unions and F# records keep the internal representation public, so this only works in cases where all values of the internal representation are valid. If you need to define a primitive type that does some checks, then you need a type that hides its internals. In this particular case, I would just use a pretty much direct F# equivalent of your C# code:

type JobId private (id:string) = 
  member x.Value = id 
  static member Create() =
    JobId(Guid.NewGuid().ToString("N"))

  static member Create(id:Guid) =
    if id = Guid.Empty then None
    else Some(new JobId(id.ToString("N")))

  static member Create(id:string) =
    try JobId.Create(Guid(id))
    with :? FormatException -> None

请注意,有两种情况需要防范-一种是string值,它实际上不是Guid,另一种是空的Guid.您可以使用类型系统来防止出现第一种情况-只需创建一个值Guid而不是string的DU!

Note that there are two cases that you want to protect against - one is string value that's not actually a Guid and the other is an empty Guid. You can use the type system to protect against the first case - just create a DU where the value is Guid rather than string!

type JobId = 
  | JobId of Guid

A,无法确保此guid不为空.但是,比以上方法更好的解决方案是定义NonEmptyGuid(使用类似上述的类),该方法仅表示非空guid.那么您的域模型可能是:

Alas, there is no way of ensuring that this guid is not empty. However, a nicer solution than the above might be to define NonEmptyGuid (using a class like above) that represents only non-empty guids. Then your domain model could be:

type JobId = 
  | JobId of NonEmptyGuid

如果您在项目中的其他地方使用NonEmptyGuid,则特别好.

This would be especially nice if you were using NonEmptyGuid elsewhere in your project.

这篇关于如何建立符合业务规则的F#类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆