簡體   English   中英

從C#調用F#時,OO替代F#中的多態性

[英]OO alternative to polymorphism in F# when calling F# from C#

我想創建一個庫,它將使用用戶定義的函數創建對象,並使用另一個用戶定義的函數進行修改。

我有一個OCaml背景,看到一個相當簡單的方法來實現它:

//user side
type userType = { mutable time : float }

let userInitialization () = { time = 0. }    
let userModification t = t.time <- t.time+1.

//my side
let algo initialization modification n =
    let a = Array.init n (fun _ -> initialization ())
    modification a.[0]
    a

問題是我希望從C#中輕松調用該庫:將函數作為參數可能是一個壞主意。

接口和抽象類(將由userType繼承)似乎是通常的OO解決方案,但如果我不知道(尚未定義的)userType在我的函數內部進行初始化步驟,則無法初始化對象。

我能想到的唯一解決方法是向用戶詢問他的userType實例作為用於調用初始化的參數,但這似乎非常不優雅。

有沒有辦法解決這個問題?

您可以定義這樣的界面:

type IInitAndModify<'T> =
    abstract member CreateNew : unit -> 'T
    abstract member Modify : item : 'T -> unit

也許還有一個用戶可以用來將它傳遞給你的實現的對象:

type Algo<'T> () =
    member this.Execute (initAndModify : IInitAndModify<'T>, n) =
        algo initAndModify.CreateNew initAndModify.Modify n

從C#開始,它看起來像這樣:

public interface IInitAndModify<T>
{
    T CreateNew();
    void Modify(T item);
}

public class Algo<T>
{
    public Algo();

    public T[] Execute(IInitAndModify<T> initAndModify, int n);
}

客戶端開發人員可以像這樣使用它:

public class UserType
{
    public float Time { get; set; }
}

public class UserInitAndModify : IInitAndModify<UserType>
{
    public UserType CreateNew()
    {
        return new UserType { Time = 0 };
    }

    public void Modify(UserType item)
    {
        item.Time++;
    }
}

並寫一個這樣的程序:

static void Main(string[] args)
{
    var a = new Algo<UserType>();
    var values = a.Execute(new UserInitAndModify(), 10);
    foreach (var v in values)
        Console.WriteLine(v.Time);
}

運行上面的Main方法時,輸出如下:

1
0
0
0
0
0
0
0
0
0
Press any key to continue . . .

我傾向於拒絕你不應該在暴露給C#的庫中公開函數作為參數的想法,這樣做變得非常普遍,你只需要看看LINQ,TPL等等。我不會想太多C#開發人員會因此而害怕。

但是,我建議你避免使用帶有cur的參數向C#公開函數,因為這些函數根本不方便使用。

您可以非常輕松地將算法包裝在一個接受tupled形式的參數的函數中,並將System.FuncSystem.Action公開給C#。

let csAlgo (initialisationFunc : System.Func<'a>, 
            modificationFunc : System.Action<'a>, 
            n : int) =
    algo (initialisationFunc.Invoke) (modificationFunc.Invoke) n

在C#中你可以這樣做:

var res = Module.csAlgo(() => new UserType(0), t => t.Time = t.Time + 1, 16);

另外,您還可以使用CompiledName屬性來獲得每種語言的套管約定。 標記你的功能

[<CompiledName("ExampleFunction")>]
let exampleFunction () = 1

然后在C#中,它看起來像這樣:

var num = Module.ExampleFunction();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM