我正在玩F#和C#,並想從C#調用F#代碼。從C調用F#代碼
我設法讓它在Visual Studio中以另一種方式工作,方法是在同一個解決方案中有兩個項目,並將C#代碼的引用添加到F#項目。做完這些之後,我可以調用C#代碼,甚至在調試時一步步完成。
我想要做的是F#代碼從C#而不是C#代碼從F#。我在F#項目中添加了一個對C#項目的引用,但它不像之前那樣工作。我想知道這是否可能,而無需手動進行。
我正在玩F#和C#,並想從C#調用F#代碼。從C調用F#代碼
我設法讓它在Visual Studio中以另一種方式工作,方法是在同一個解決方案中有兩個項目,並將C#代碼的引用添加到F#項目。做完這些之後,我可以調用C#代碼,甚至在調試時一步步完成。
我想要做的是F#代碼從C#而不是C#代碼從F#。我在F#項目中添加了一個對C#項目的引用,但它不像之前那樣工作。我想知道這是否可能,而無需手動進行。
(編輯:我最初鏈接到這些文件外部,但我的SVN主機不再允許匿名訪問。因此,代碼現在內聯在這回答r)
下面是從C#調用F#的一個工作示例。
正如您所遇到的,我無法通過從「添加引用...項目」選項卡中進行選擇來添加引用。相反,我必須通過在「添加引用...瀏覽」選項卡中瀏覽到F#程序集來手動執行此操作。
------ 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#單元測試用於模塊-----
// 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);
}
}
}
謝謝。 「我必須通過瀏覽到'添加引用...瀏覽'選項卡中的F#程序集手動執行此操作。」是什麼爲我工作。 – ZeroKelvin 2009-01-26 00:52:01
從this link他們似乎有一些可能的解決方案,但似乎最簡單的是this comment之一:
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#代碼:
int a = Module1.f3(Module1.f2, 10, 20); // method gets converted to the delegate automatically in C#
我在val行上得到一個錯誤:val f3:FCallback - > int - > int - > int「錯誤定義中意外的關鍵字'val'在此點或其他標記之前或之前預期的不完整結構化構造。 – 2011-11-14 20:50:29
它不應該'只是工作「,儘管在從C#作品引用項目之前可能必須構建F#項目(我忘記了)。
問題的一個常見來源是名稱空間/模塊。如果你的F#代碼不是以一個名字空間聲明開始的,它將被放入一個與文件名同名的模塊中,例如,從C#開始,你的類型可能會顯示爲「Program.Foo」而不是「Foo」(如果Foo是Program.fs中定義的F#類型)。
感謝您提供有關模塊名稱的信息:)。 – ZeroKelvin 2009-01-26 01:18:22
// 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中:
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);
除非有特定的問題,增加從C#一個今天「只是工作的F#項目的引用」。這裏沒有什麼特別的,因爲這是.NET架構(語言不可知論,MSIL等)的基本承諾或好處之一。事實上,相反會很奇怪。你對這個賞金還有什麼期望? – 2018-03-09 07:19:23