在F#中声明私有静态成员?

时间:2010-04-11 22:49:42

标签: c# class f#

我决定将下面的C#中的课程移植到F#作为练习。

很难。我只注意到三个问题

1)问候是可见的 2)我不能让v成为静态类变量 3)我不知道如何在构造函数中设置greet成员。

我如何解决这些问题?代码应该足够相似,我不需要更改任何C#源代码。 ATM仅限Test1.v = 21;不起作用

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CsFsTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Test1.hi("stu");
            new Test1().hi();
            Test1.v = 21;
            var a = new Test1("Stan");
            a.hi();
            a.a = 9;

            Console.WriteLine("v = {0} {1} {2}", a.a, a.b, a.NotSTATIC());
        }
    }
    class Test1
    {
        public int a;
        public int b { get { return a * 2; } }
        string greet = "User";
        public static int v;

        public Test1() {}
        public Test1(string name) { greet = name; }

        public static void hi(string greet) { Console.WriteLine("Hi {0}", greet); }
        public void hi() { Console.WriteLine("Hi {0} #{1}", greet, v); }
        public int NotSTATIC() { return v; }
    }
}

F#

namespace CsFsTest

type Test1 = 
    (*
        public int a;
        public int b { get { return a * 2; } }
        string greet = "User";
        public static int v;
    *)
    [<DefaultValue>]
    val mutable a : int
    member x.b = x.a * 2
    member x.greet = "User" (*!! Needs to be private *)

    [<DefaultValue>]
    val mutable v : int (*!! Needs to be static *)

    (*
        public Test1() {}
        public Test1(string name) { greet = name; }
    *)
    new () = {}
    new (name) = { }

    (*  
        public static void hi(string greet) { Console.WriteLine("Hi {0}", greet); }
        public void hi() { Console.WriteLine("Hi {0} #{1}", greet, v); }
        public int NotSTATIC() { return v; }
    *)   
    static member hi(greet) = 
        printfn "hi %s" greet
    member x.hi() =
        printfn "hi %s #%i" x.greet x.v
    member x.NotSTATIC() =
        x.v

3 个答案:

答案 0 :(得分:10)

F#语言有一些在C#中没有任何等价物的构造,但它几乎可以在C#中使用。这意味着如果您只是将代码从C#转换为F#,那么您最终只会使用F#的一个子集。因此,有时候寻找一些特定的F#构造会更好。

我认为这也是静态成员的情况。除了类之外,您还可以使用模块组织F#代码,模块提供了一种自然的方式来声明静态数据和函数。以下是问候模块的示例:

// modules are automatically 'static' (from the C# point of viedw)
module Greetings = 
  // public mutable field inside a module
  let mutable how = "Hello "
  // global function that uses the field
  let greet name = 
    Console.WriteLine(how + name)

// modify the global field and invoke global function
Greetings.how <- "Ahoj "
Greetings.greet("Tomas")

如果您需要一些静态功能和一些实例功能,通常很容易在模块和标准类之间拆分功能。显而易见的好处是它为您提供了更简单的语法,但它也可以帮助构建代码:

type Person(name) =
  member GreetMe() = 
    Greetings.greet(name)

如果要将模块中的成员隐藏起来,可以将其声明为privateinternal。例如,如果您只想使how字段对程序集可访问,则可以写:

let mutable internal how = "Hello "  

我认为这会为您提供更多惯用的F#代码,因此在编写F#代码时我可能更喜欢这种编程风格。如果您打算在C#中使用它,那么模块将显示为静态类,它们也很容易使用。

作为旁注,通常建议避免使用太多可变成员。但是,如果您将它们用于某种配置,那么我认为它没问题。

答案 1 :(得分:5)

下面是一些针对C#客户端编译的F#。

在.NET中,很少公开公共领域;我会建议反对它。用于公开字段的F#语法有点麻烦。

namespace CsFsTest

open System

type Test1 =
    val mutable private greet : string
    [<DefaultValue>]
    val mutable public a : int
    [<DefaultValue>]
    static val mutable private vv : int

    static member v with get() = Test1.vv 
                    and set(x) = Test1.vv <- x

    member this.b = this.a*2
    static member hi(greet:string) = Console.WriteLine("Hi {0}", greet)
    member this.hi() = Console.WriteLine("Hi {0} #{1}", this.greet, Test1.v)

    new() = { greet = "User" }
    new(name : string) = { greet = name }

    member this.NotSTATIC() = Test1.v

答案 2 :(得分:2)

您将greet定义为属性。它不需要是一个。

// these are the same
member x.greet = "User" 
member x.greet with get() = "User"

它可以只是一个变量。

val mutable private greet : string
new () = { greet = "User" }
new (name) = { greet = name }

F#不允许您拥有公共静态类变量。你必须使用一个getter / setter。