gpt4 book ai didi

.net - 在 F# 中,是否有使用用于相等和排序比较的主键创建记录类型的快捷方式?

转载 作者:行者123 更新时间:2023-12-04 20:34:33 25 4
gpt4 key购买 nike

我知道 F# 编译器可以生成 IEquatable<T> 的默认实现。和 IComparable<T> ,以及覆盖默认值 GetHashCodeEquals记录和类的方法。但相比之下,这些实现使用了所有字段。我需要创建一些 DTO 类型,其中相等性和排序顺序应仅基于主键字段。有没有一些方便的机制,比如这个属性?

这是我的课:
(我可能犯了一些 F# 语法错误。还是有点新的。)

type Customer() =
member val Id = 0 with get, set
member val Name = "" with get, set
member val PhoneNumber = "" with get, set

我可以做这样的事情:
[<CompareByKey>]
type Customer() =
[<PrimaryKey>] member val Id = 0 with get, set
member val Name = "" with get, set
member val PhoneNumber = "" with get, set

而不是这个:
type Customer() =
member val Id = 0 with get, set
member val Name = "" with get, set
member val PhoneNumber = "" with get, set

override Equals(obj) =
match obj with
| :? Customer as c -> this.Id = c.Id
| _ -> false

override GetHashCode() = hash this.Id

interface IEquatable<Customer> with
member Equals(c) = this.Id = c.Id

interface IComparable<Customer> with
member CompareTo(c) = this.Id.CompareTo(c.Id)

编辑:

我认为这可能是使用抽象基类在 C# 中更好地解决的问题。 (也可以在 F# 中实现,但它有点开始变得不习惯了。)
public abstract class EntityBase<TEntity> : 
IEquatable<TEntity>,
IComparable<TEntity>
where TEntity : EntityBase<TEntity> {

protected EntityBase(int id) {
this.Id = id;
}

public int Id { get; }

public sealed override int GetHashCode() => Id.GetHashCode();

public sealed override bool Equals(object obj) =>
Equals(this, obj as TEntity);

public bool Equals(TEntity other) =>
(other != null) && (this.Id == other.Id);

public int CompareTo(TEntity other) =>
(other == null) ? 1 : this.Id.CompareTo(other.Id);

}

最佳答案

您可以使用反射来拉出主键。反射可能很昂贵,因此请确保您只收到一次调用来搜索每种类型的键(我在下面的代码中留下了一些 printfn 以便我可以仔细检查)

open System
[<AttributeUsage(AttributeTargets.Property)>]
type PrimaryKeyAttribute() =
inherit Attribute()
[<CLIMutable()>]
type Customer =
{
[<PrimaryKey>]
Id: int
Name: string
}
let getPrimaryKey<'T, 'U when 'U:> IComparable> (): 'T -> 'U =
printfn "Starting to search for keys."
typeof<'T>.GetProperties()
|> Seq.tryFind (fun p ->
let attr = p.GetCustomAttributes(typeof<PrimaryKeyAttribute>, false)
attr.Length > 0
)
|> function
| Some p ->
(fun t -> p.GetMethod.Invoke(t, [| |]) :?> 'U)
| _ -> failwith "No PrimaryKey attribute found"

对客户列表进行排序现在变为:
let customers = 
[
{ Id = 4; Name = "Alice" }
{ Id = 1; Name = "Eve" }
{ Id = 1; Name = "Charlie" }
{ Id = 1; Name = "Bob" }
]
let sorted =
customers
|> List.sortBy (getPrimaryKey())

你会得到:
val sorted : Customer list =
[{Id = 1;
Name = "Eve";}; {Id = 1;
Name = "Charlie";}; {Id = 1;
Name = "Bob";}; {Id = 4;
Name = "Alice";}]

而正常排序会给你鲍勃;查理;前夕;爱丽丝。您可能需要预先计算每种类型的 key getter:
let getCustomerKey<'U when 'U:> IComparable> : Customer -> 'U = 
getPrimaryKey()
let sorted2 =
customers
|> List.sortBy getCustomerKey

而且,正如其他人已经指出的, [<CLIMutable()>]在处理依赖于默认构造函数和变异的代码时很有帮助。见 documentation here

关于.net - 在 F# 中,是否有使用用于相等和排序比较的主键创建记录类型的快捷方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38257283/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com