2009-03-31 10 views
31

Si vous deviez définir des méthodes d'extension, des propriétés dans un assembly écrites en F #, puis utiliser cet assembly en C#, verriez-vous les extensions définies en C#?Méthodes d'extension F # en C#

Si oui, ce serait tellement cool.

+1

Voir aussi http://cs.hubfs.net/forums/thread/13967.aspx – Brian

Répondre

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

Cette méthode pourrait être utilisée en C# uniquement en ajoutant l'espace de noms (using using) au fichier où il sera utilisé.

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

Here is a link to the original blogpost.

Répondre à la question dans les commentaires "Extension Méthodes statiques":

namespace ExtensionFSharp 

module CollectionExtensions = 

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

En F # vous l'appelez comme ceci:

open System.Linq 
open ExtensionFSharp.CollectionExtensions 

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

En C# vous l'appelez comme ainsi:

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); 
      } 
     } 
    } 

Maintenant, donnez-moi ma médaille!

+0

Merci, mais qu'en est-il des propriétés d'extension d'instance et des méthodes statiques, ainsi que des propriétés d'extension statique? Seraient-ils appelés aussi? La raison pour laquelle j'ai posé cette question est parce que, je sais que C# a seulement des méthodes d'extension d'instance. –

+0

Merci, viens de voir ta mise à jour. –

+0

Vous méritez certainement une médaille pour la créativité avec la réflexion et peut-être en 2009 c'était la seule façon. Cependant, vous pouvez maintenant utiliser ['CompiledNameAttribute'] (http://stackoverflow.com/a/39678801/111575) pour une approche beaucoup plus simple et sécurisée pour appeler F # à partir de C#. – Abel

6

par les language spec, l'article 10.7 "extensions de type":

membres d'extension en option sont le sucre syntaxique pour les membres statiques. Les utilisations de membres d'extension optionnels élaborent des appels à des membres statiques avec des noms codés où l'objet est passé en premier argument. L'encodage des noms n'est pas spécifié dans cette version de F # et n'est pas compatible avec les encodages C# des membres d'extension C#

+0

Savez-vous s'il est prévu d'unifier les moyens d'implémentation des extensions de type F # et C#? Ce serait bien si l'on n'avait pas besoin d'utiliser les attributs supplémentaires. – Joh

+0

Il ne semble pas que nous fassions cela pour la première version de F # (par exemple, pas dans le calendrier VS2010). – Brian

14

Malgré mon autre réponse, je l'ai juste essayé avec le CTP F # (sur VS shell) et C# Express de ma boîte à la maison (! tous ses outils de développement), et cela fonctionne:

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 
    } 
} 

Je ne savais pas que vous pouvez le faire; chouette. Crédit à @alex.

+1

Merci, mais n'est-ce pas juste une méthode d'extension d'instance? –

+0

Merci, j'étais plus intéressé par d'autres extensions de F # à apparaître en C#, mais votre autre réponse sorte d'adresses qui. –

3

Pour une raison quelconque, la réponse acceptée suggère d'utiliser la réflexion pour obtenir une méthode d'extension de type F #. Puisque le nom de la méthode compilée est différent entre les versions de F #, et peut être différent selon les arguments, inlining et autres problèmes liés au nommage, je suggère plutôt d'utiliser CompiledNameAttribute à la place, ce qui est beaucoup plus facile et se confond facilement avec C#. En outre, aucune réflexion (et ses problèmes de performance et de sécurité) n'est nécessaire.

Supposons que vous ayez ceci en F #:

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

Vous ne seriez pas en mesure d'appeler cela directement et la version compilée ressemblerait à ceci (selon si oui ou non il y a des surcharges):

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); 
    } 
} 

Si vous n'utilisez pas la réflexion, vous ne pouvez pas accéder à la méthode String.ToInteger.Static.Cependant, une décoration simple méthode avec le CompiledNameAttribute résout ce problème:

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

Maintenant, la méthode compilée ressemble à ceci dans le réflecteur, marquer le changement de nom compilé:

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); 
    } 
} 

Vous pouvez toujours utiliser cette méthode comme vous êtes habitué à F # (comme String.ToInteger dans ce cas). Mais plus important encore, vous pouvez maintenant utiliser cette méthode sans réflexion ou autre supercherie de C#:

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

Et bien sûr, vous pouvez vous rendre la vie plus simple en ajoutant un alias de type en C# pour le module Foo.Bar.StringExt:

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

Ce n'est pas la même chose qu'une méthode d'extension, et la décoration du membre statique avec un attribut System.Runtime.CompilerServices.Extension est ignorée. C'est simplement un moyen simple d'utiliser type extensions à partir d'autres langages .NET. Si vous voulez une méthode d'extension "authentique" qui semble agir sur le type, utilisez la syntaxe let des autres réponses ici.