当前位置:  开发笔记 > 编程语言 > 正文

从C#调用F#代码

如何解决《从C#调用F#代码》经验,为你挑选了3个好方法。

我正在玩F#和C#,并希望从C#调用F#代码.

我设法让它在Visual Studio中以相反的方式工作,方法是在同一个解决方案中有两个项目,并在F#项目中添加C#代码的引用.这样做之后,我可以调用C#代码,甚至在调试时逐步执行它.

我想要做的是F#代码来自C#而不是来自F#的C#代码.我在C#项目中添加了对F#项目的引用,但它的工作方式与以前不同.我想知道如果不手动完成这是否可行.



1> Eric..:

(编辑:我最初在外部链接到这些文件,但我的SVN主机不再允许匿名访问.所以代码现在在这个答案中内联.)

下面是从C#调用F#的工作示例.

正如您所遇到的那样,我无法通过从"添加引用...项目"选项卡中进行选择来添加引用.相反,我必须通过在"添加引用...浏览"选项卡中浏览到F#程序集来手动完成.

------ F#MODULE -----

// 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测试模块-----

// 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
        {
            public static List mkList(params T[] ar)
            {
                List foo = List.Nil;
                for (int n = ar.Length - 1; n >= 0; n--)
                    foo = List.Cons(ar[n], foo);
                return foo;
            }
        }


        [Test]
        public void foldl1()
        {
            int seed = 64;
            List values = Helper.mkList( 4, 2, 4 );
            FastFunc> fn =
                FuncConvert.ToFastFunc( (Converter) delegate( int a, int b ) { return a/b; } );

            int result = Zumbro.foldl( fn, seed, values);
            Assert.AreEqual(2, result);
        }

        [Test]
        public void foldl0()
        {
            string seed = "hi mom";
            List values = Helper.mkList();
            FastFunc> fn =
                FuncConvert.ToFastFunc((Converter)delegate(string a, string b) { throw new Exception("should never be invoked"); });

            string result = Zumbro.foldl(fn, seed, values);
            Assert.AreEqual(seed, result);
        }

        [Test]
        public void map()
        {
            FastFunc fn =
                FuncConvert.ToFastFunc((Converter)delegate(int a) { return a*a; });

            List vals = Helper.mkList(1, 2, 3);
            List res = Zumbro.map(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 vals = Helper.mkList("arnold", "BOB", "crAIg");
            List exp = Helper.mkList( "ARNOLD", "BOB", "CRAIG" );
            List 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);
        }

    }
}



2> Brian..:

它应该"正常工作",尽管你可能必须在C#的项目到项目引用工作之前构建F#项目(我忘了).

常见问题的根源是命名空间/模块.如果你的F#代码没有以名称空间声明开头,那么它会被放入一个与文件名同名的模块中,所以例如来自C#你的类型可能显示为"Program.Foo"而不仅仅是"Foo"(如果是Foo)是Program.fs中定义的F#类型.


感谢您提供有关模块名称的信息:)。
是的,我需要博客那个,它会导致很多混乱.

3> Chris Bunch..:

从这个链接他们似乎有许多可能的解决方案,但似乎最简单的解决方案是:

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#

推荐阅读
小色米虫_524
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有