And*_*rew 1 generics f# c#-to-f#
我试图在F#中的类中创建一个公共方法.C#中的等价物是:
public void MyMethod<T>(string name, Thing<T> thingToProcess)
{
// Do stuff
}
Run Code Online (Sandbox Code Playgroud)
在F#中,我正在尝试:
member public this.MyMethod<'T>((name : System.String), (thingToProcess : Thing<'T>)) =
(* Do similar stuff *)
()
Run Code Online (Sandbox Code Playgroud)
此代码生成编译器错误:
错误FS0670:此代码不够通用.类型变量'T无法推广,因为它会逃避其范围.
如果我尝试以下,我可以编译:
member public this.MyMethod((name : System.String), (thingToProcess : Thing<_>)) =
(* Some code *)
()
Run Code Online (Sandbox Code Playgroud)
但是,尝试从C#调用方法如下所示失败:
public void DoSomething<T>(Thing<T> thingToProcess)
{
_instanceOfFSharpClass.MyMethod("A string", thingToProcess);
}
Run Code Online (Sandbox Code Playgroud)
编译错误:
'MyFSharpClass.MyMethod(string,Thing)'的最佳重载方法匹配包含一些无效参数.
建议?如何在F#中创建这种类型的方法?如果无法在F#中创建此方法,那么什么是合理的解决方法?我需要避免铸造Thing<T>到Thing<object>,如果在所有可能的.
编辑:
这里有更多的F#代码.我会尽力坚持可能相关的部分.EnumWithFlags是一个C#程序集的枚举[FlagsAttribute]. cacheOne填充在此处未列出的其他方法中. IInterface在C#程序集中定义,只有一个方法,void ReceiveThing<T>(string name, Thing<T> thingToProcess).该功能TranslateThing有签名val TranslateThing : (Guid -> Thing<'T> -> TranslatedThing<'T>).这有帮助吗?
type TranslatedThing<'T> =
| FirstThing of Thing<'T>
| SecondThing of Thing<System.String>
| ThirdThing of Thing<byte[]>
| FourthThing of Thing<System.String>
| IgnoreThing
[<AbstractClass>]
type public MyAbstractClass() =
let cacheOne = new ConcurrentDictionary<EnumWithFlags, Dictionary<Guid, IInterface>>()
member public this.MyMethod<'T>((name : System.String), (thingToProcess : Thing<'T>)) =
cacheOne.Keys.Where(fun key -> match key with
| k when (k &&& thingToProcess.EnumWithFlagsProperty) = EnumWithFlags.None -> false
| _ -> true)
.SelectMany(fun key -> cacheOne.[key].AsEnumerable())
.Distinct(
{
new IEqualityComparer<KeyValuePair<Guid, IInterface>> with
member x.Equals(a, b) = a.Key = b.Key
member x.GetHashCode y = y.Key.GetHashCode()
})
.AsParallel()
.Select(new Func<KeyValuePair<Guid, IInterface>, Tuple<IInterface, TranslatedThing<_>>>(fun kvp -> new Tuple<IInterface, TranslatedThing<'T>>(kvp.Value, TranslateThing kvp.Key thingToProcess)))
.Where(new Func<Tuple<IInterface, TranslatedThing<'T>>, bool>(fun t -> t.Item2 <> IgnoreThing))
.ForAll(new Action<Tuple<IInterface, TranslatedThing<'T>>>(fun t ->
match t.Item2 with
| FirstThing(x) -> t.Item1.ReceiveThing(name, x)
| SecondThing(x) -> t.Item1.ReceiveThing(name, x)
| ThirdThing(x) -> t.Item1.ReceiveThing(name, x)
| FourthThing(x) -> t.Item1.ReceiveThing(name, x)
| _ -> ()))
Run Code Online (Sandbox Code Playgroud)
另一个编辑:
经过多次蒸馏后,我想我大致看到了造成这个问题的原因.我离开了最后一行,MyMethod因为把它取出并没有解决错误.这一行是:
cacheTwo.Remove(thingToProcess) |> ignore
Run Code Online (Sandbox Code Playgroud)
在cacheTwo类的前面定义的位置:
let cacheTwo = new Dictionary<Thing<'T>, SpecificThingTranslator<'T>>
Run Code Online (Sandbox Code Playgroud)
签名SpecificThingTranslator<'T>是:
type SpecificThingTranslator<'T> =
{First: TranslatedThing<'T>;
Second: Lazy<TranslatedThing<'T>>;
Third: Lazy<TranslatedThing<'T>>;
Fourth: Lazy<TranslatedThing<'T>>;}
Run Code Online (Sandbox Code Playgroud)
消除该cacheTwo行并没有解决错误,因为函数最终TranslateThing指的是cacheTwo.消除所有引用以cacheTwo消除错误.
我可以找到一个映射Thing<'T>到的解决方法SpecificThingTranslator<'T>.不过,我错过了什么吗?我是否忘记了允许这种映射的.NET集合(或者可能是特定于F#的集合)?虽然键的类型参数和每对的值必须相同,但每个KeyValuePair(或等效的)可以具有不同的类型参数.
代码的另一部分肯定有问题.以下最小样本具有完全相同的定义MyMethod并且工作正常(粘贴到新脚本文件中时):
type Thing<'T> = T of 'T
type Foo() =
member this.MyMethod<'T>(name:string, thingToProcess:Thing<'T>) =
()
Run Code Online (Sandbox Code Playgroud)
我删除了public修饰符,因为这是F#中成员的默认值,我也删除了其他括号,但是没有任何改变....
| 归档时间: |
|
| 查看次数: |
1120 次 |
| 最近记录: |