导出到其他 .NET 语言时,何时在 F# 中使用驼峰命名法?
When will I use camelCase in F# when exporting to other .NET languages?
基于The F# Component Design Guidelines,F# 应使用PascalCase
以符合.NET Framework 命名约定。
假设我正在使用 C# 或 VB.NET 并且想要导入 F# 库,我应该什么时候期望 camelCase
约定出现在该库中?
看看FsCheck library, and specifically its Gen module。 (FsCheck 源代码中还有其他示例,但这个示例很容易阅读)。 FsCheck 旨在从 F# 和 C# 中使用,Gen 模块的设计反映了:
module Gen =
// ...
[<CompiledName("Map"); EditorBrowsable(EditorBrowsableState.Never)>]
let map f (gen:Gen<_>) = gen.Map f
[<CompiledName("Sized"); EditorBrowsable(EditorBrowsableState.Never)>]
let sized fgen = Gen (fun n r -> let (Gen m) = fgen n in m n r)
[<CompiledName("Sized"); CompilerMessage("This method is not intended for use from F#.", 10001, IsHidden=true, IsError=false)>]
let sizedFunc (sizedGen : Func<int,Gen<_>>) =
sized sizedGen.Invoke
暂时忽略这些函数的实现,看看它们的名字,以及各自赋予的CompiledName
属性。当您从 F# 调用 map
函数时,您将调用它作为 Gen.map
,但是当您从 C# 使用它时,CompiledName
属性将使您看到它的名称为 Gen.Map
。与 sized
函数类似,从 F# 代码调用时将调用 Gen.sized
,从 C# 调用时将以名称 Gen.Sized
显示。另请注意第二个函数如何具有相同的 CompiledName
(从 C# 看),但 F# 代码在 Gen.sized
和 Gen.sizedFunc
之间有区别(并且 F# 编译器也会警告您如果您尝试使用 Gen.sizedFunc
那 "This method is not intended for use from F#"),因为该重载需要 C# 代码使用的函数类型,并且纯粹是为了方便 C# 编码人员使用该库。 (F# 函数使用 FSharpFunc
类型,在某些情况下其行为不同于 C# Func
类型)。
然而,您的问题并没有那么多"How should I write my F# library so that it can be used by C# coders?"。相反,您的问题是,"As a C# coder, what should I expect from F# libraries in terms of naming conventions?"那个问题的答案是:这取决于您使用的库。
正如您所指出的,F# 组件设计指南建议将 PascalCase 名称用于设计用于调用代码的函数。 FsCheck 是一个很好的图书馆例子。但并不是所有的库都是为了便于从 C# 使用而编写的。有些库在编写时仅考虑使用它们的其他 F# 代码,这些库不一定 符合设计指南,因为 F# 约定是对函数名称使用驼峰式命名。
所以虽然这不是一个完全令人满意的答案,但它是我能给你的最好的答案,因为我不知道你将使用哪些库。
基于The F# Component Design Guidelines,F# 应使用PascalCase
以符合.NET Framework 命名约定。
假设我正在使用 C# 或 VB.NET 并且想要导入 F# 库,我应该什么时候期望 camelCase
约定出现在该库中?
看看FsCheck library, and specifically its Gen module。 (FsCheck 源代码中还有其他示例,但这个示例很容易阅读)。 FsCheck 旨在从 F# 和 C# 中使用,Gen 模块的设计反映了:
module Gen =
// ...
[<CompiledName("Map"); EditorBrowsable(EditorBrowsableState.Never)>]
let map f (gen:Gen<_>) = gen.Map f
[<CompiledName("Sized"); EditorBrowsable(EditorBrowsableState.Never)>]
let sized fgen = Gen (fun n r -> let (Gen m) = fgen n in m n r)
[<CompiledName("Sized"); CompilerMessage("This method is not intended for use from F#.", 10001, IsHidden=true, IsError=false)>]
let sizedFunc (sizedGen : Func<int,Gen<_>>) =
sized sizedGen.Invoke
暂时忽略这些函数的实现,看看它们的名字,以及各自赋予的CompiledName
属性。当您从 F# 调用 map
函数时,您将调用它作为 Gen.map
,但是当您从 C# 使用它时,CompiledName
属性将使您看到它的名称为 Gen.Map
。与 sized
函数类似,从 F# 代码调用时将调用 Gen.sized
,从 C# 调用时将以名称 Gen.Sized
显示。另请注意第二个函数如何具有相同的 CompiledName
(从 C# 看),但 F# 代码在 Gen.sized
和 Gen.sizedFunc
之间有区别(并且 F# 编译器也会警告您如果您尝试使用 Gen.sizedFunc
那 "This method is not intended for use from F#"),因为该重载需要 C# 代码使用的函数类型,并且纯粹是为了方便 C# 编码人员使用该库。 (F# 函数使用 FSharpFunc
类型,在某些情况下其行为不同于 C# Func
类型)。
然而,您的问题并没有那么多"How should I write my F# library so that it can be used by C# coders?"。相反,您的问题是,"As a C# coder, what should I expect from F# libraries in terms of naming conventions?"那个问题的答案是:这取决于您使用的库。
正如您所指出的,F# 组件设计指南建议将 PascalCase 名称用于设计用于调用代码的函数。 FsCheck 是一个很好的图书馆例子。但并不是所有的库都是为了便于从 C# 使用而编写的。有些库在编写时仅考虑使用它们的其他 F# 代码,这些库不一定 符合设计指南,因为 F# 约定是对函数名称使用驼峰式命名。
所以虽然这不是一个完全令人满意的答案,但它是我能给你的最好的答案,因为我不知道你将使用哪些库。