2009-03-31 14 views
31

Jeśli miałbyś zdefiniować niektóre metody rozszerzania, właściwości w zespole napisane w F #, a następnie użyć tego zestawu w C#, czy widziałbyś zdefiniowane rozszerzenia w C#?F # metody rozszerzenia w C#

Jeśli tak, to byłoby takie fajne.

+1

Zobacz także http://cs.hubfs.net/forums/thread/13967.aspx – Brian

Odpowiedz

45
[<System.Runtime.CompilerServices.Extension>] 
module Methods = 
    [<System.Runtime.CompilerServices.Extension>] 
    let Exists(opt : string option) =     
    match opt with 
     | Some _ -> true     
     | None -> false 

Ta metoda może być używana tylko w języku C# przez dodanie przestrzeni nazw (przy użyciu przy użyciu) do pliku, w którym będzie używana.

if (p2.Description.Exists()) { ...} 

Here is a link to the original blogpost.

Odpowiadając na pytanie w komentarzach "Rozbudowa Metody statyczne":

namespace ExtensionFSharp 

module CollectionExtensions = 

    type System.Linq.Enumerable with 
    static member RangeChar(first:char, last:char) = 
     {first .. last} 

w F # to nazwać tak:

open System.Linq 
open ExtensionFSharp.CollectionExtensions 

let rangeChar = Enumerable.RangeChar('a', 'z') 
printfn "Contains %i items" rangeChar.CountItems 

W języku C# to nazwać jak więc:

using System; 
using System.Collections.Generic; 
using ExtensionFSharp; 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var method = typeof (CollectionExtensions).GetMethod("Enumerable.RangeChar.2.static"); 


      var rangeChar = (IEnumerable<char>) method.Invoke(null, new object[] {'a', 'z'}); 
      foreach (var c in rangeChar) 
      { 
       Console.WriteLine(c); 
      } 
     } 
    } 

A teraz daj mi mój szalony medal!

+0

Dzięki, ale co z właściwościami rozszerzeń instancji i metodami statycznymi oraz właściwościami statycznych rozszerzeń? Czy oni też zostaną wezwani? Powodem, dla którego o to pytałem jest to, ponieważ wiem, że C# ma tylko metody rozszerzenia instancji. –

+0

Dzięki, właśnie zobaczyłem twoją aktualizację. –

+0

Zdecydowanie zasługujesz na medal za kreatywną drogę z refleksją i być może w 2009 roku był to jedyny sposób. Jednak możesz teraz użyć ['CompiledNameAttribute'] (http://stackoverflow.com/a/39678801/111575) dla znacznie prostszego i bezpieczniejszego podejścia do wywoływania F # z C#. – Abel

6

Per ze language spec, rozdział 10.7 "rozszerzeń typu":

opcjonalne członkowie przedłużające są cukier syntaktyczny dla członków statycznych. Zastosowania opcjonalnych elementów rozszerzeń rozwijają się do wywołań statycznych członków o zakodowanych nazwach, gdzie obiekt jest przekazywany jako pierwszy argument. Kodowanie nazw nie jest określone w tym wydaniu F # i nie jest kompatybilne z kodowaniami C# z członków rozszerzenia C#

+0

Czy wiesz, że istnieją plany ujednolicenia sposobów implementacji rozszerzeń typu F # i C#. Byłoby miło, gdyby nie trzeba było używać dodatkowych atrybutów. – Joh

+0

Nie wygląda na to, że zrobimy to dla pierwszej wersji F # (np. Nie w ramce czasowej VS2010). – Brian

14

Pomimo mojej drugiej odpowiedzi, po prostu próbowałem tego z F # CTP (na powłoce VS) i C# Express z moje okno w domu (! Wszystkie bezpłatnych narzędzi dev), a to działa:

F #

#light 
namespace MyFSharp 

// C# way 
[<System.Runtime.CompilerServices.Extension>] 
module ExtensionMethods = 
    [<System.Runtime.CompilerServices.Extension>] 
    let Great(s : System.String) = "Great" 

    // F# way 
    type System.String with 
     member this.Awesome() = "Awesome" 
    let example = "foo".Awesome()   

C#

using System; 
using MyFSharp; // reference the F# dll 
class Program 
{ 
    static void Main(string[] args) 
    { 
     var s = "foo"; 
     //s.Awesome(); // no 
     Console.WriteLine(s.Great()); // yes 
    } 
} 

nie byłem świadomy można to zrobić; sprytny. Podziękowania dla @alex.

+1

Dzięki, ale czy nie jest to tylko metoda rozszerzenia instancji? –

+0

Dzięki, byłem bardziej zainteresowany innymi rozszerzeniami F #, aby pokazać się w C#, ale twój inny rodzaj adresów odpowiedzi, które. –

3

Z jakiegoś powodu przyjęta odpowiedź sugeruje użycie odbicia, aby uzyskać metodę rozszerzenia typu F #. Ponieważ nazwa skompilowanej metody jest różna w różnych wersjach F # i może być różna w zależności od argumentów, inliningu i innych kwestii związanych z nazewnictwem, wolałbym raczej zaproponować użycie CompiledNameAttribute, co jest znacznie łatwiejsze i łatwo wtapia się w C#. Poza tym nie ma potrzeby refleksji (i jej wydajności oraz kwestii bezpieczeństwa typu).

Załóżmy, że masz to w F #:

namespace Foo.Bar 
module StringExt = 
    type System.String with 
     static member ToInteger s = System.Int64.Parse(s) 

nie byłaby w stanie wywołać tego bezpośrednio, a wersja skompilowana będzie wyglądać następująco (w zależności od tego, czy występują przeciążenia):

namespace Foo.Bar 
{ 
    using Microsoft.FSharp.Core; 
    using System; 

    [CompilationMapping(SourceConstructFlags.Module)] 
    public static class StringExt 
    { 
     public static long String.ToInteger.Static(string s) => 
      long.Parse(s); 
    } 
} 

Jeśli nie używasz odbicia, nie możesz uzyskać dostępu do metody String.ToInteger.Static.Jednak prosta metoda dekoracji z CompiledNameAttribute rozwiązuje ten problem:

namespace Foo.Bar 
module StringExt = 
    type System.String with 
     [<CompiledName("ToInteger")>] 
     static member ToInteger s = System.Int64.Parse(s) 

Teraz skompilowany metoda wygląda to w reflektor zaznaczyć zmiany w skompilowanej nazwa:

namespace Foo.Bar 
{ 
    using Microsoft.FSharp.Core; 
    using System; 

    [CompilationMapping(SourceConstructFlags.Module)] 
    public static class StringExt 
    { 
     [CompilationSourceName("ToInteger")] 
     public static long ToInteger(string s) => 
      long.Parse(s); 
    } 
} 

można nadal korzystać z tego sposób w jaki jesteś przyzwyczajony w F # (jako String.ToInteger w tym przypadku). Ale co ważniejsze, można teraz korzystać z tej metody bez refleksji lub innego oszustwa z C#:

var int x = Foo.Bar.StringExt.ToInteger("123"); 

I oczywiście, można uczynić swoje życie prostszym dodając typ aliasu w C# dla modułu Foo.Bar.StringExt:

using Ext = Foo.Bar.StringExt; 
.... 
var int x = Ext.ToInteger("123"); 

To nie jest to samo co metoda rozszerzenia, a dekorowanie elementu statycznego atrybutem System.Runtime.CompilerServices.Extension zostaje zignorowane. Jest to po prostu prosty sposób użycia type extensions z innych języków .NET. Jeśli chcesz "prawdziwą" metodę rozszerzenia, która wydaje się działać na typ, użyj let -syntax z innych odpowiedzi tutaj.

Powiązane problemy