2016-06-04 19 views
7

Chcę utworzyć bibliotekę, która utworzy obiekty za pomocą funkcji zdefiniowanej przez użytkownika i zmodyfikuje je za pomocą innej funkcji zdefiniowanej przez użytkownika.OO alternatywa dla polimorfizmu w F # podczas wywoływania F # z C#

mam tła SML i zobaczyć dość prosty sposób, aby je realizować:

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

Problemem jest to, że chcę, że biblioteka będzie łatwe do połączenia z C#: mający funkcje jak argumentów jest chyba zły pomysł.

Klasa interfejsu i abstrakcyjna (która byłaby dziedziczona przez userType) wydaje się być zwyczajnym rozwiązaniem OO, ale nie mogę zainicjować obiektu, jeśli nie znam (jeszcze nieokreślonego) userType wykonującego krok inicjowania, w moim funkcja, niemożliwe.

Jedynym sposobem obejścia tego problemu jest zapytanie użytkownika o instancję jego userType jako argumentu, który byłby używany do wywołania inicjalizacji, ale wydaje się to bardzo nieeleganckie.

Czy istnieje sposób rozwiązania tego problemu?

+2

Bądź interfejs rodzajowe? –

+1

Jeśli spodziewasz się dużego użycia C#, prawdopodobnie korzystasz z interfejsu, ale jest też 'Microsoft.FSharp.Core.FuncConvert' do konwersji między C#' Functions' lub 'Actions' i F #' FSharpFuncs'. Możesz użyć tego na stronie C# wraz z bieżącym kodem. – scrwtp

Odpowiedz

5

Można zdefiniować interfejs tak:

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

a być może także obiektu użytkownik może użyć, aby przekazać go do realizacji:

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

z C#, wygląda to tak:

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

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

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

programista klient mógł go używać tak:

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

i napisać program tak:

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

Uruchamiając powyższy Main metodę, wyjście to:

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

Dokładnie tego szukałem, dziękuję! –

5

byłbym skłonny odrzucić pomysł, że powinnam 'eksponuj funkcje jako argumenty w bibliotece wystawionej na C#, staje się to dość powszechne, wystarczy spojrzeć na LINQ, TPL, itp. Nie sądzę, żeby zbyt wielu programistów C# było tym przerażonych.

Chciałbym jednak zasugerować, aby unikać eksponowania funkcji z curry argumentów do C#, ponieważ nie są one w ogóle wygodne do pracy.

Możesz dość łatwo zawinąć swój algorytm w funkcję, która akceptuje argumenty w formie z kraciastą i wystawia System.Func i System.Action s na C#.

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

w C# można następnie to zrobić:

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

Jako mały bok, można również użyć atrybutu CompiledName aby można dostać się w konwencje obudowy prawo w każdym języku.Oznaczyć czynność

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

potem w C#, wygląda to tak:

var num = Module.ExampleFunction(); 
+1

Dziękuję za odpowiedź, mam wrażenie, że programista C# będzie raczej podawał interfejs zorientowany obiektowo, ale oznaczysz, że mam zamiar zachować w pamięci. –