简体   繁体   English

在 F# 中定义静态类

[英]Defining static classes in F#

Is it possible to define a static class that contains overloadable members in F#?是否可以在 F# 中定义包含可重载成员的静态类? let module bindings cannot be overloaded, even though they are compiled into static static members in static classes. let模块绑定不能被重载,即使它们被编译成静态类中的静态静态成员。

type declerations can contain static members, but I don't know if the type itself can be made static. type可以包含静态成员,但我不知道类型本身是否可以设为静态。

My current solution is to define a type with a private constructor and just use that.我目前的解决方案是用私有构造函数定义一个type ,然后使用它。 I'm wondering if there is a way I can define a static type as I want.我想知道是否有一种方法可以根据需要定义静态类型。

As Robert Jeppeson pointed out, a "static class" in C# is just short-hand for making a class that cannot be instantiated or inherited from, and has only static members.正如 Robert Jeppeson 指出的那样,C# 中的“静态类”只是创建一个不能实例化或继承的类的简写,并且只有静态成员。 Here's how you can accomplish exactly that in F#:以下是在 F# 中完全实现这一点的方法:

[<AbstractClass; Sealed>]
type MyStaticClass private () =
    static member SomeStaticMethod(a, b, c) =
       (a + b + c)

    static member SomeStaticMethod(a, b, c, d) =
       (a + b + c + d)

This might be a little bit of overkill, as both the AbstractClass and the private constructor will prevent you from creating an instance of the class, however, this is what C# static classes do - they are compiled to an abstract class with a private constructor.这可能有点矫枉过正,因为AbstractClass和私有构造函数都会阻止您创建类的实例,但是,这就是 C# 静态类所做的 - 它们被编译为具有私有构造函数的抽象类。 The Sealed attribute prevents you from inheriting from this class. Sealed属性阻止您从此类继承。

This technique won't cause a compiler error if you add instance methods the way it would in C#, but from a caller's point of view there is no difference.如果您像在 C# 中那样添加实例方法,此技术不会导致编译器错误,但从调用者的角度来看,没有区别。

This is explained in The F# Component Design Guidelines .这在F# 组件设计指南 中进行了解释

[<AbstractClass; Sealed>]
type Demo =
    static member World = "World"
    static member Hello() = Demo.Hello(Demo.World)
    static member Hello(name: string) = sprintf "Hello %s!" name

let s1 = Demo.Hello()
let s2 = Demo.Hello("F#")

It is still possible to define instance methods, but you can't instantiate the class when there is no constructor available.仍然可以定义实例方法,但是当没有可用的构造函数时,您无法实例化该类。

edit Jan 2021 : See the comment from Abel, and the linked issue. 2021 年 1 月编辑:请参阅 Abel 的评论和相关问题。 Joel Mueller's answer seems to be the best advice so far, but things will perhaps change in the future.迄今为止,乔尔·穆勒 (Joel Mueller) 的回答似乎是最好的建议,但未来可能会发生变化。

I'm not sure there is such a thing as a static class.我不确定是否有静态类之类的东西。 'static' on class level in C# was introduced in 2.0, I believe, mostly as convenience (avoid private constructors and compile-time checking that no instance members are present).我相信,C# 类级别上的“静态”是在 2.0 中引入的,主要是为了方便(避免私有构造函数和编译时检查不存在实例成员)。 You can't examine the type and conclude that it is static: http://msdn.microsoft.com/en-us/library/system.reflection.typeinfo.aspx您无法检查类型并得出它是静态的结论: http : //msdn.microsoft.com/en-us/library/system.reflection.typeinfo.aspx

Update: MSDN declares a static class is a class that is sealed and has only static members: http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.80).aspx更新:MSDN 声明静态类是一个密封类并且只有静态成员: http : //msdn.microsoft.com/en-us/library/79b3xss3(v=vs.80).aspx

So, what you're doing at the moment is the way to do it.所以,你现在正在做的就是做这件事的方法。

There is no facility for defining static types in F#.在 F# 中没有定义静态类型的工具。

The first alternative is to define a module, but it lacks the capability of overloading functions (which is what you're after).第一种选择是定义一个模块,但它缺乏重载函数的能力(这就是你所追求的)。 The second alternative is to declare a normal type with static members.第二种选择是声明一个带有静态成员的普通类型。

Regarding the second approach, it is exactly what the accepted answer to your old question described.关于第二种方法,这正是您对旧问题所接受的答案所描述的。 I refactor the code to explain it easier.我重构了代码以更容易地解释它。 First, a dummy single-case discreminated unions is defined:首先,定义了一个虚拟的单案例歧视联合:

type Overloads = Overloads

Second, you exploit the fact that static members can be overloaded:其次,您利用静态成员可以重载的事实:

type Overloads with
    static member ($) (Overloads, m1: #IMeasurable) = fun (m2: #IMeasurable) -> m1.Measure + m2.Measure 
    static member ($) (Overloads, m1: int) = fun (m2: #IMeasurable) -> m1 + m2.Measure

Third, you propagate constraints of these overloaded methods to let-bounds using inline keyword:第三,使用inline关键字将这些重载方法的约束传播到 let-bounds:

let inline ( |+| ) m1 m2 = (Overloads $ m1) m2

When you're able to overload let-bounds using this method, you should create a wrapper module to hold these functions and mark your type private .当您能够使用此方法重载 let-bounds 时,您应该创建一个包装模块来保存这些函数并将您的类型标记为private

I think the problem here is trying to make F# into C#.我认为这里的问题是试图将 F# 变成 C#。 If the problem can't be solved in a non imperative fashion use C# or write an object oriented library and use it in F#.如果问题不能以非命令式方式解决,请使用 C# 或编写一个面向对象的库并在 F# 中使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM