Joa*_*nge 35 c# extension-methods f#
如果要定义一些扩展方法,用F#编写的程序集中的属性,然后在C#中使用该程序集,您会在C#中看到已定义的扩展吗?
如果是这样,那就太酷了.
ale*_*lex 48
[<System.Runtime.CompilerServices.Extension>]
module Methods =
[<System.Runtime.CompilerServices.Extension>]
let Exists(opt : string option) =
match opt with
| Some _ -> true
| None -> false
Run Code Online (Sandbox Code Playgroud)
只有通过将命名空间(使用using)添加到将使用它的文件中,才能在C#中使用此方法.
if (p2.Description.Exists()) { ...}
Run Code Online (Sandbox Code Playgroud)
在评论"扩展静态方法"中回答问题:
namespace ExtensionFSharp
module CollectionExtensions =
type System.Linq.Enumerable with
static member RangeChar(first:char, last:char) =
{first .. last}
Run Code Online (Sandbox Code Playgroud)
在F#中,您可以这样称呼它:
open System.Linq
open ExtensionFSharp.CollectionExtensions
let rangeChar = Enumerable.RangeChar('a', 'z')
printfn "Contains %i items" rangeChar.CountItems
Run Code Online (Sandbox Code Playgroud)
在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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,给我一个惊人的勋章!
Bri*_*ian 16
尽管我的另一个答案是,我只是尝试使用F#CTP(在VS shell上)和C#Express从我家里的盒子(所有免费开发工具!),这样做:
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()
Run Code Online (Sandbox Code Playgroud)
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
}
}
Run Code Online (Sandbox Code Playgroud)
我不知道你能做到这一点; 俏皮.感谢@alex.
出于某种原因,已接受的答案建议使用反射来获取 F# 类型的扩展方法。由于 F# 版本之间编译的方法名称不同,并且可能因参数、内联和其他与命名相关的问题而异,我宁愿建议使用CompiledNameAttribute
它,这样更容易,并且很容易与 C# 融合。此外,不需要反射(及其性能和类型安全问题)。
假设你在 F# 中有这个:
namespace Foo.Bar
module StringExt =
type System.String with
static member ToInteger s = System.Int64.Parse(s)
Run Code Online (Sandbox Code Playgroud)
您将无法直接调用它,编译后的版本将如下所示(取决于是否存在重载):
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);
}
}
Run Code Online (Sandbox Code Playgroud)
除非您使用反射,否则您无法访问该方法String.ToInteger.Static
。然而,一个简单的方法装饰CompiledNameAttribute
解决了这个问题:
namespace Foo.Bar
module StringExt =
type System.String with
[<CompiledName("ToInteger")>]
static member ToInteger s = System.Int64.Parse(s)
Run Code Online (Sandbox Code Playgroud)
现在编译的方法在 Reflector 中看起来是这样的,标记编译名称的变化:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
您仍然可以按照在 F# 中习惯的方式使用此方法(如String.ToInteger
本例中所示)。但更重要的是,您现在可以使用此方法而无需反射或 C# 中的其他技巧:
var int x = Foo.Bar.StringExt.ToInteger("123");
Run Code Online (Sandbox Code Playgroud)
当然,您可以通过在 C# 中为Foo.Bar.StringExt
模块添加类型别名来使您的生活更简单:
using Ext = Foo.Bar.StringExt;
....
var int x = Ext.ToInteger("123");
Run Code Online (Sandbox Code Playgroud)
这与扩展方法不同,使用System.Runtime.CompilerServices.Extension
属性装饰静态成员会被忽略。这只是使用来自其他 .NET 语言的类型扩展的一种简单方法。如果您想要一个似乎对类型起作用的“真正”扩展方法,请使用let
此处其他答案中的-syntax。
归档时间: |
|
查看次数: |
5939 次 |
最近记录: |