2016-06-04 14 views
7

Tôi muốn tạo thư viện sẽ tạo đối tượng bằng cách sử dụng hàm do người dùng xác định và sửa đổi chúng bằng cách sử dụng hàm do người dùng xác định khác.OO thay thế cho đa hình trong F # khi gọi F # từ C#

Tôi có một nền OCaml và nhìn thấy một cách khá đơn giản để thực hiện nó:

//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 

Vấn đề là tôi muốn thư viện mà là dễ dàng để gọi từ C#: có chức năng như các đối số có lẽ là một xấu ý kiến.

Lớp giao diện và lớp trừu tượng (có thể được kế thừa bởi userType) có vẻ là giải pháp OO thông thường, nhưng tôi không thể khởi tạo đối tượng nếu tôi không biết userType (chưa được xác định) thực hiện bước khởi tạo, bên trong chức năng, không thể.

Cách giải quyết duy nhất mà tôi có thể nghĩ là yêu cầu người dùng cho một phiên bản userType làm đối số được sử dụng để gọi khởi tạo, nhưng điều đó có vẻ rất không phù hợp.

Có cách nào để giải quyết vấn đề này không?

+2

Hãy giao diện chung chung? –

+1

Nếu bạn mong đợi việc sử dụng C# nặng, bạn có thể tốt hơn với giao diện, nhưng cũng có 'Microsoft.FSharp.Core.FuncConvert' để chuyển đổi giữa C#' Funcs' hoặc 'Actions' và F #' FSharpFuncs'. Bạn có thể sử dụng nó trên C# bên cùng với mã hiện tại của bạn. – scrwtp

Trả lời

5

Bạn có thể định nghĩa một giao diện như thế này:

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

và có lẽ cũng là một đối tượng người dùng có thể sử dụng để vượt qua nó để thực hiện của bạn:

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

Từ C#, nó trông như thế này:

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

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

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

Nhà phát triển khách hàng có thể sử dụng nó như thế này:

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++; 
    } 
} 

và viết một chương trình như thế này:

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); 
} 

Khi chạy Main phương pháp trên, sản lượng là thế này:

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

Đó chính xác là những gì tôi đang tìm kiếm, cảm ơn bạn! –

5

Tôi xin được nghiêng để từ chối ý tưởng rằng bạn shouldn không hiển thị các chức năng như các đối số trong một thư viện tiếp xúc với C#, nó trở nên khá phổ biến để làm như vậy, bạn chỉ cần xem LINQ, TPL, v.v. Tôi không nghĩ rằng quá nhiều C# phát triển sẽ sợ hãi bởi điều đó.

Tuy nhiên, tôi khuyên bạn tránh hiển thị các chức năng với các đối số được kết hợp với C# vì các tính năng này không thuận tiện để làm việc.

Bạn có thể dễ dàng quấn thuật toán của mình trong một hàm chấp nhận các đối số ở dạng đã lập và hiển thị System.FuncSystem.Action s tới C#.

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

trong C# sau đó bạn có thể làm điều này:

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

Là một nhỏ sang một bên, bạn cũng có thể sử dụng thuộc tính CompiledName để bạn có thể nhận ước vỏ của bạn ngay trong từng ngôn ngữ.Tag chức năng của bạn

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

Sau đó, trong C#, nó trông như thế này:

var num = Module.ExampleFunction(); 
+1

Cảm ơn câu trả lời của bạn, tôi có cảm giác rằng một nhà phát triển C# muốn thay đổi giao diện hướng đối tượng nhưng bạn đánh dấu một số điểm tốt mà tôi sẽ giữ trong bộ nhớ. –