2009-03-31 44 views
31

Nếu bạn định nghĩa một số phương thức mở rộng, thuộc tính trong một assembly được viết bằng F #, và sau đó sử dụng assembly đó trong C#, bạn có thấy các phần mở rộng đã xác định trong C# không?Phương thức mở rộng F # trong C#

Nếu có, điều đó thật tuyệt.

+1

Xem thêm http://cs.hubfs.net/forums/thread/13967.aspx – Brian

Trả lời

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

Phương pháp này chỉ có thể được sử dụng trong C# bằng cách thêm không gian tên (sử dụng) vào tệp sẽ được sử dụng.

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

Here is a link to the original blogpost.

Trả lời câu hỏi trong ý kiến ​​"mở rộng phương pháp tĩnh":

namespace ExtensionFSharp 

module CollectionExtensions = 

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

Trong F # bạn gọi nó như vậy:

open System.Linq 
open ExtensionFSharp.CollectionExtensions 

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

Trong C# bạn gọi nó như như vậy:

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

Bây giờ, hãy cho tôi huy chương kỳ quái của tôi!

+0

Cảm ơn bạn, nhưng về đặc tính mở rộng dụ và phương pháp tĩnh và thuộc tính mở rộng tĩnh thì sao? Họ sẽ được gọi là quá? Lý do tôi hỏi điều này là bởi vì, tôi biết rằng C# chỉ có các phương thức mở rộng thể hiện. –

+0

Cảm ơn bạn, chỉ nhìn thấy cập nhật của bạn. –

+0

Bạn chắc chắn xứng đáng có một huy chương cho cách sáng tạo với sự phản ánh và có lẽ trong năm 2009 đó là cách duy nhất. Tuy nhiên, bây giờ bạn có thể sử dụng ['CompiledNameAttribute'] (http://stackoverflow.com/a/39678801/111575) để có cách tiếp cận đơn giản và an toàn hơn cho việc gọi F # từ C#. – Abel

6

mỗi sự language spec, phần 10,7 "Loại phần mở rộng":

thành viên mở rộng bắt buộc là cú pháp đường cho các thành viên tĩnh. Sử dụng các thành viên mở rộng tùy chọn xây dựng cho các cuộc gọi đến các thành viên tĩnh với các tên được mã hóa, nơi đối tượng được chuyển làm đối số đầu tiên. Mã hóa tên không được chỉ định trong bản phát hành F # này và không tương thích với mã hóa C# của các thành viên mở rộng C#

+0

Bạn có biết nếu có kế hoạch thống nhất các phương pháp triển khai kiểu F # và C#. Sẽ thật tuyệt nếu một người không cần sử dụng các thuộc tính phụ. – Joh

+0

Có vẻ như chúng tôi sẽ không làm điều này cho phiên bản đầu tiên của F # (ví dụ: không nằm trong khung thời gian của VS2010). – Brian

14

Mặc dù câu trả lời khác của tôi, tôi đã thử với F # CTP (trên vỏ VS) và C# Express từ hộp của tôi ở nhà (! tất cả các công cụ dev miễn phí), và các công trình này:

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

tôi không biết bạn có thể làm điều này; tiện lợi. Ghi có vào @alex.

+1

Cảm ơn, nhưng không phải đây chỉ là một phương pháp mở rộng thể hiện? –

+0

Cảm ơn, tôi đã quan tâm nhiều hơn đến các phần mở rộng khác của F # để hiển thị trong C#, nhưng loại trả lời khác của bạn về địa chỉ đó. –

3

Vì một số lý do, câu trả lời được chấp nhận đề xuất sử dụng phản chiếu để có phương thức mở rộng loại F #. Vì tên phương thức được biên dịch khác nhau giữa các phiên bản của F # và có thể khác nhau tùy thuộc vào các đối số, nội tuyến và các vấn đề đặt tên khác, tôi muốn thay vì sử dụng CompiledNameAttribute, dễ dàng hơn và dễ dàng hòa trộn với C#. Bên cạnh đó, không cần sự phản ánh (và các vấn đề an toàn về hiệu suất và loại của nó).

Giả sử bạn có điều này trong F #:

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

Bạn sẽ không thể gọi đây là trực tiếp và phiên bản biên soạn sẽ trông như thế này (tùy thuộc vào có hay không có quá tải):

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

Trừ khi bạn sử dụng phản chiếu, bạn không thể truy cập phương thức String.ToInteger.Static.Tuy nhiên, một phương pháp trang trí đơn giản với CompiledNameAttribute giải quyết vấn đề này:

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

Bây giờ phương pháp biên soạn trông như thế này trong Reflector, đánh dấu sự thay đổi trong tên biên soạn:

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

Bạn vẫn có thể sử dụng này phương pháp theo cách bạn đang sử dụng trong F # (như String.ToInteger trong trường hợp này). Nhưng quan trọng hơn, bây giờ bạn có thể sử dụng phương pháp này mà không suy nghĩ hoặc thủ đoạn gian trá khác từ C#:

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

Và dĩ nhiên, bạn có thể làm cho cuộc sống của bạn đơn giản bằng cách thêm một loại bí danh trong C# cho Foo.Bar.StringExt mô-đun:

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

Điều này không giống như một phương pháp mở rộng và trang trí thành viên tĩnh với thuộc tính System.Runtime.CompilerServices.Extension bị bỏ qua. Đây chỉ là một cách đơn giản để sử dụng type extensions từ các ngôn ngữ .NET khác. Nếu bạn muốn phương thức tiện ích mở rộng "chính hãng" có vẻ hoạt động trên loại, hãy sử dụng let -syntax từ các câu trả lời khác tại đây.

Các vấn đề liên quan