2013-10-11 5 views
10

in F #, possiamo creare una funzione come questa:Chiamare un F # spuntato il nome della funzione con spazi incorporati (`` XXX YY``) da C#

let ``add x and y`` x y = x + y 

e posso chiamare normalmente come questo:

``add x and y`` 1 2 

C'è un modo per chiamare la funzione sopra dal lato C#? Non riuscivo però a vederlo in Object Browser.

+0

Riflessione? Potrebbe essere l'unico modo. –

+0

Grazie. Ci stavo pensando, ma renderà il codice più difficile da leggere. Penso che potrei semplicemente re-associare la funzione con il nome C# -friendly invece. – kimsk

risposta

15

È possibile esporre qualsiasi valid F # nome della funzione di C# come qualsiasi C# nome di funzione valido utilizzando CompiledName attributo:

namespace Library1 
module Test = 
    [<CompiledName("Whatever")>] 
    let ``add a and b`` x y = x + y 

e poi in C#:

using Library1; 
............... 
System.Console.WriteLine(Test.Whatever(2,2)); 

FOLLOW-UP 03/05/2016 su commento da NickL, si applica almeno a F # 3.1:

Mo dalle funzioni ai membri porta alcuni "se e ma".

Per cominciare, l'attributo CompiledName non viene compilato con member se utilizzato da puro namespace. La semplice compilazione richiede l'uso all'interno di uno module.

quando viene utilizzato all'interno di un module e decorare metodomember di F # di registrazione funziona bene a prescindere di come i contenuti tra due zecche sembra. Tuttavia quando decorare proprietàmember di F # record di CompiledName è visibile cross-assemblaggio solo se contenuti tra doppie zecche assomiglia qualche nome valore legale:

module M 

type MyRecord = 
    { myField: string } 
    [<CompiledName "Whatever">] 
    member x.``Blah Blah blah``() = x.myField 
    [<CompiledName "Another">] 
    member x.``ABC`` = x.myField 

e poi da C# le seguenti opere OK:

var recInC = new M.MyRecord("Testing..."); 
Console.WriteLine(recInC.Whatever()); 
Console.WriteLine(recInC.Another); 

Tali incongruenze richiedono potenziali issues.

+0

Ah, sapevo che c'era qualche attributo là fuori che l'ha fatto. –

+0

Funziona per le proprietà dei tipi di record? – NickL

+0

@NickL: vedere il seguito della risposta originale. –

6

La riflessione potrebbe essere l'unico modo, ma non deve essere brutto da usare. Basta avvolgere tutto in un corso per riflettere.

public static class MyModuleWrapper 
{ 
    // it would be easier to create a delegate once and reuse it 
    private static Lazy<Func<int, int, int>> addXAndY = new Lazy<Func<int, int, int>>(() => 
     (Func<int, int, int>)Delegate.CreateDelegate(typeof(Func<int, int, int>), typeof(MyModule).GetMethod("add x and y")) 
    ); 
    public static int AddXAndY(int x, int y) 
    { 
     return addXAndY.Value(x, y); 
    } 

    // pass other methods through. 
    public static int OtherMethod(int x, int y) 
    { 
     return MyModule.OtherMethod(x, y); 
    } 
} 

Quindi usarlo normalmente.

var sum = MyModuleWrapper.AddXAndY(1, 2); 
var otherValue = MyModuleWrapper.OtherMethod(1, 2); // use the wrapper instead 

io non sono sicuro di quello che deve essere cambiato o come se ci sono tipi polimorfi coinvolti, ma si spera che si ottiene l'idea e in grado di applicare le modifiche necessarie.