从 C# 调用 F# 代码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/478531/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Call F# code from C#
提问by ZeroKelvin
I am playing around with F# and C#, and would like to call F# code from C#.
我正在玩 F# 和 C#,并想从 C# 调用 F# 代码。
I managed to get it to work the other way around in Visual Studio by having two projects in the same solution, and adding a reference of the C# code to the F# project. After doing this, I could call C# code and even step through it while debugging.
通过在同一个解决方案中有两个项目,并将 C# 代码的引用添加到 F# 项目,我设法让它在 Visual Studio 中以相反的方式工作。执行此操作后,我可以调用 C# 代码,甚至可以在调试时单步执行。
What I am trying to do is F# code FROM C# instead of C# code from F#. I added a reference to the F# project to the C# project, but it isn't working the way it did before. I would like to know if this is possible without doing it manually.
我想要做的是来自 C# 的 F# 代码,而不是来自 F# 的 C# 代码。我向 C# 项目添加了对 F# 项目的引用,但它无法像以前那样工作。我想知道这是否可以不手动进行。
采纳答案by Eric
Below is a working example of calling F# from C#.
下面是一个从 C# 调用 F# 的工作示例。
As you encountered, I was not able to add a reference by selecting from the "Add Reference ... Projects" tab. Instead I did have to do it manually, by browsing to the F# assembly in the "Add Reference ... Browse" tab.
正如您所遇到的,我无法通过从“添加引用...项目”选项卡中进行选择来添加引用。相反,我确实必须手动完成,方法是在“添加引用...浏览”选项卡中浏览到 F# 程序集。
------ F# MODULE -----
------ F# 模块 -----
// First implement a foldl function, with the signature (a->b->a) -> a -> [b] -> a
// Now use your foldl function to implement a map function, with the signature (a->b) -> [a] -> [b]
// Finally use your map function to convert an array of strings to upper case
//
// Test cases are in TestFoldMapUCase.cs
//
// Note: F# provides standard implementations of the fold and map operations, but the
// exercise here is to build them up from primitive elements...
module FoldMapUCase.Zumbro
#light
let AlwaysTwo =
2
let rec foldl fn seed vals =
match vals with
| head :: tail -> foldl fn (fn seed head) tail
| _ -> seed
let map fn vals =
let gn lst x =
fn( x ) :: lst
List.rev (foldl gn [] vals)
let ucase vals =
map String.uppercase vals
----- C# UNIT TESTS FOR THE MODULE -----
----- 模块的 C# 单元测试 -----
// Test cases for FoldMapUCase.fs
//
// For this example, I have written my NUnit test cases in C#. This requires constructing some F#
// types in order to invoke the F# functions under test.
using System;
using Microsoft.FSharp.Core;
using Microsoft.FSharp.Collections;
using NUnit.Framework;
namespace FoldMapUCase
{
[TestFixture]
public class TestFoldMapUCase
{
public TestFoldMapUCase()
{
}
[Test]
public void CheckAlwaysTwo()
{
// simple example to show how to access F# function from C#
int n = Zumbro.AlwaysTwo;
Assert.AreEqual(2, n);
}
class Helper<T>
{
public static List<T> mkList(params T[] ar)
{
List<T> foo = List<T>.Nil;
for (int n = ar.Length - 1; n >= 0; n--)
foo = List<T>.Cons(ar[n], foo);
return foo;
}
}
[Test]
public void foldl1()
{
int seed = 64;
List<int> values = Helper<int>.mkList( 4, 2, 4 );
FastFunc<int, FastFunc<int,int>> fn =
FuncConvert.ToFastFunc( (Converter<int,int,int>) delegate( int a, int b ) { return a/b; } );
int result = Zumbro.foldl<int, int>( fn, seed, values);
Assert.AreEqual(2, result);
}
[Test]
public void foldl0()
{
string seed = "hi mom";
List<string> values = Helper<string>.mkList();
FastFunc<string, FastFunc<string, string>> fn =
FuncConvert.ToFastFunc((Converter<string, string, string>)delegate(string a, string b) { throw new Exception("should never be invoked"); });
string result = Zumbro.foldl<string, string>(fn, seed, values);
Assert.AreEqual(seed, result);
}
[Test]
public void map()
{
FastFunc<int, int> fn =
FuncConvert.ToFastFunc((Converter<int, int>)delegate(int a) { return a*a; });
List<int> vals = Helper<int>.mkList(1, 2, 3);
List<int> res = Zumbro.map<int, int>(fn, vals);
Assert.AreEqual(res.Length, 3);
Assert.AreEqual(1, res.Head);
Assert.AreEqual(4, res.Tail.Head);
Assert.AreEqual(9, res.Tail.Tail.Head);
}
[Test]
public void ucase()
{
List<string> vals = Helper<string>.mkList("arnold", "BOB", "crAIg");
List<string> exp = Helper<string>.mkList( "ARNOLD", "BOB", "CRAIG" );
List<string> res = Zumbro.ucase(vals);
Assert.AreEqual(exp.Length, res.Length);
Assert.AreEqual(exp.Head, res.Head);
Assert.AreEqual(exp.Tail.Head, res.Tail.Head);
Assert.AreEqual(exp.Tail.Tail.Head, res.Tail.Tail.Head);
}
}
}
回答by Chris Bunch
From this linkthey seem to have a number of possible solutions, but the one that seemed the simplest was a comment:
从这个链接他们似乎有许多可能的解决方案,但似乎最简单的一个是评论:
F# Code:
F# 代码:
type FCallback = delegate of int*int -> int;;
type FCallback =
delegate of int * int -> int
let f3 (f:FCallback) a b = f.Invoke(a,b);;
val f3 : FCallback -> int -> int -> int
C# Code:
C# 代码:
int a = Module1.f3(Module1.f2, 10, 20); // method gets converted to the delegate automatically in C#
回答by Brian
It should 'just work', though you might have to build the F# project before a project-to-project reference from C# works (I forget).
它应该“正常工作”,尽管您可能必须在 C# 的项目到项目引用工作之前构建 F# 项目(我忘记了)。
A common source of issues is namespaces/modules. If your F# code does not start with a namespace declaration, it gets put in a module with the same name as the filename, so that e.g. from C# your type might appear as "Program.Foo" rather than just "Foo" (if Foo is an F# type defined in Program.fs).
一个常见的问题来源是命名空间/模块。如果您的 F# 代码没有以命名空间声明开头,则会将其放入与文件名同名的模块中,因此例如从 C# 中,您的类型可能显示为“Program.Foo”而不仅仅是“Foo”(如果 Foo是在 Program.fs 中定义的 F# 类型)。
回答by merrais
// Test.fs :
// 测试文件:
module meGlobal
type meList() =
member this.quicksort = function
| [] -> [] // if list is empty return list
| first::rest ->
let smaller,larger = List.partition((>=) first) rest
List.concat[this.quicksort smaller; [first]; this.quicksort larger]
// Test.cs :
// 测试.cs :
List<int> A = new List<int> { 13, 23, 7, 2 };
meGlobal.meList S = new meGlobal.meList();
var cquicksort = Microsoft.FSharp.Core.FSharpFunc<FSharpList<IComparable>, FSharpList<IComparable>>.ToConverter(S.quicksort);
FSharpList<IComparable> FI = ListModule.OfSeq(A.Cast<IComparable>());
var R = cquicksort(FI);