我想创建一个库,它将使用用户定义的函数创建对象,并使用另一个用户定义的函数进行修改.
我有一个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
Run Code Online (Sandbox Code Playgroud)
问题是我希望从C#中轻松调用该库:将函数作为参数可能是一个坏主意.
接口和抽象类(将继承userType)似乎是通常的OO解决方案,但如果我不知道(尚未定义的)userType在我的函数内部进行初始化步骤,我就无法初始化对象.
我能想到的唯一解决方法是向用户询问他userType作为参数的实例,该实例将用于调用初始化,但这似乎非常不优雅.
有没有办法解决这个问题?
您可以定义这样的界面:
type IInitAndModify<'T> =
abstract member CreateNew : unit -> 'T
abstract member Modify : item : 'T -> unit
Run Code Online (Sandbox Code Playgroud)
也许还有一个用户可以用来将它传递给你的实现的对象:
type Algo<'T> () =
member this.Execute (initAndModify : IInitAndModify<'T>, n) =
algo initAndModify.CreateNew initAndModify.Modify n
Run Code Online (Sandbox Code Playgroud)
从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);
}
Run Code Online (Sandbox Code Playgroud)
客户端开发人员可以像这样使用它:
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++;
}
}
Run Code Online (Sandbox Code Playgroud)
并写一个这样的程序:
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);
}
Run Code Online (Sandbox Code Playgroud)
运行上面的Main方法时,输出是这样的:
1
0
0
0
0
0
0
0
0
0
Press any key to continue . . .
Run Code Online (Sandbox Code Playgroud)
我倾向于拒绝你不应该在暴露给C#的库中公开函数作为参数的想法,这样做变得非常普遍,你只需要看看LINQ,TPL等等.我不会想太多C#开发人员会因此而害怕.
但是,我建议你避免使用带有cur的参数向C#公开函数,因为这些函数根本不方便使用.
您可以非常轻松地将算法包装在一个函数中,该函数接受以tupled形式接受的参数并公开System.Func和转换System.Action为C#.
let csAlgo (initialisationFunc : System.Func<'a>,
modificationFunc : System.Action<'a>,
n : int) =
algo (initialisationFunc.Invoke) (modificationFunc.Invoke) n
Run Code Online (Sandbox Code Playgroud)
在C#中你可以这样做:
var res = Module.csAlgo(() => new UserType(0), t => t.Time = t.Time + 1, 16);
Run Code Online (Sandbox Code Playgroud)
另外,您还可以使用该CompiledName属性来获得每种语言的套管约定.标记你的功能
[<CompiledName("ExampleFunction")>]
let exampleFunction () = 1
Run Code Online (Sandbox Code Playgroud)
然后在C#中,它看起来像这样:
var num = Module.ExampleFunction();
Run Code Online (Sandbox Code Playgroud)