将表达式和lambdas参数传递给F#中的C#扩展方法
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了将表达式和lambdas参数传递给F#中的C#扩展方法,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5189字,纯文字阅读大概需要8分钟。
内容图文
我正在努力解决这个问题,因为我只是F#的初学者,目前我正在学习F#,通过在F#中为C#代码创建单元测试,如F#所示,以获得乐趣和利润.
问题.
我有以下C#类
public class ObjectMapper<TSource, TTarget>
where TTarget : class, new() {
public readonly TSource Source;
public readonly TTarget Target;
public ObjectMapper(TSource source) {
this.Source = source;
this.Target = new TTarget();
}
public ObjectMapper<TSource, TTarget> Populate<T>(
Expression<Func<TTarget, T>> targetAccessor,
Func<TSource, T> sourceValue) {
var targetPropertyInfo = targetAccessor.ToPropertyInfo();
targetPropertyInfo.SetValue(this.Target, sourceValue(this.Source));
return this;
}
}
我开始尝试在F#中编写一个简单的单元测试
module CompanyName.Utils.Test.ObjectMapper
open System
open Xunit
open Swensen.Unquote
open Microsoft.FSharp.Linq.RuntimeHelpers // do I need this?
open CompanyName.Utils // the namespace of the C# class above
type Source(name: string, code: int, date: DateTime) =
member thi.Name = name
member this.Code = code
member this.Date = date
type Target() =
member this.Id: string = System.String.Empty
member this.Name: string = System.String.Empty
member this.Code: int = 0
member this.Date: DateTime = System.DateTime.MinValue
[<Fact>]
let ``ObjectMapper.Populate maps property values from source to target``() =
// arrange
let name = @"name"
let code = 123
let date = new System.DateTime(1980,2,15)
let source = Source(name, code, date)
// let target = Target()
let mapper = ObjectMapper<Source, Target>(source)
// act // this is how I would like it to be!
mapper.Populate(t => t.Name, s => s.Name)
mapper.Populate(t => t.Code, s => s.Code)
mapper.Populate(t => t.Date, s => s.Date)
mapper.Populate(t => t.Id, s => s.Date+s.Code+s.Name)
// assert
test<@ mapper.Target.Name = source.Name @>
Assert.Equal(mapper.Target.Name, source.Name)
test<@ mapper.Target.Code = source.Code @>
Assert.Equal(mapper.Target.Code, source.Code)
test<@ mapper.Target.Date = source.Date @>
Assert.Equal(mapper.Target.Date, source.Date)
test<@ mapper.Target.Id = @"1980-2-15123name" @>
Assert.Equal(mapper.Target.Id, @"1980-2-15123name")
Assert.True(false)
我的问题在于测试的断言部分,理想情况下,我希望能够像上面代码中使用的那样传递lambda.不幸的是,这根本不起作用,我试图引用其他关于堆栈溢出的帖子,其中讨论了这个和相关的主题.总的来说,这些帖子的级别对我来说有点太高了,虽然我理解了一般概念但是我没有真正掌握必要的细节来将上面的元代码转换为在F#中有意义的东西,最重要的是编译和运行.
如果你能帮助我,我将非常感激
>上面测试的断言部分通过展示它应该如何完成以及为什么元代码无法工作.
>尝试通过给出适合5岁儿童的例子来理解lambda和表达式如何在两个方向上在F#和C#之间起作用.
>我可以用来更好地理解主题的任何资源
可能以他们难度增加的方式订购.
请随意对我认为适合帮助我成为F#以及C#中更好的开发人员的代码发表任何评论,我根本不介意.我知道上面的代码非常简单,有些部分冗余且效率低下.我认为要保持基本,以免影响核心问题.
对于那些可能熟悉一种风格但不熟悉另一种风格的人,可以在Unquote和MSTest样式中重复这些断言.
非常感谢你的帮助.
下面是Fyodor Soiki解释的工作代码
module CompanyName.FSharp.UtilsFunctions
// Efficient concatenation of objects into a string with string builder
// https://stackoverflow.com/questions/18595597/is-using-a-stringbuilder-a-
right-thing-to-do-in-f
let strconc =
fun (data) ->
let sb = new System.Text.StringBuilder()
for o in data do sb.Append(o.ToString()) |> ignore
sb.ToString()
// examples
strconc ["one"; "two"] |> printfn "%s"
strconc [1;2;3] |> printfn "%s"
strconc (["one"; "two"; 3 ]: list<obj>) |> printfn "%s"
module LogXtreme.Utils.Test.ObjectMapper
open System
open Xunit
open Swensen.Unquote
open CompanyName.Utils
open CompanyName.FSharp.UtilsFunctions
type Source(name: string, code: int, date: DateTime) =
member thi.Name = name
member this.Code = code
member this.Date = date
type Target() =
member val Id: string = System.String.Empty with get, set
member val Name: string = System.String.Empty with get, set
member val Code: int = 0 with get, set
member val Date: DateTime = System.DateTime.MinValue with get, set
[<Fact>]
let ``ObjectMapper.Populate maps property values from source to target``() =
// arrange
let name = @"name"
let code = 123
let date = new System.DateTime(1980,2,15)
let source = Source(name, code, date)
let mapper = ObjectMapper<Source, Target>(source)
let expectedId = strconc ([source.Name; source.Code; source.Date]: list<obj>)
// act
mapper.Populate((fun t -> t.Name), fun s -> s.Name) |> ignore
mapper.Populate((fun t -> t.Code), fun s -> s.Code) |> ignore
mapper.Populate((fun t -> t.Date), fun s -> s.Date) |> ignore
mapper.Populate((fun t -> t.Id), fun s -> strconc ([s.Name; s.Code; s.Date]: list<obj>)) |> ignore
// assert
test<@ mapper.Target.Name = source.Name @>
test<@ mapper.Target.Code = source.Code @>
test<@ mapper.Target.Date = source.Date @>
test<@ mapper.Target.Id = expectedId @>
测试现在通过.
解决方法:
一般来说,F#往往会避免神奇的转换,因为它们通常会导致细微的,难以发现的错误.但是,在一些特殊情况下,主要是为了支持C#互操作场景,它会妥协.
特别是,当调用期望表达式< _>的对象方法时,编译器会将F#lambda表达式转换为C#引用(与C#编译器的方式相同).这意味着你可以将普通的F#lambdas传递给你的方法:
mapper.Populate( (fun t -> t.Name), fun s -> s.Name )
第一个lambda周围的括号是必要的.没有它们,整个事物被解释为有趣的t – > (t.Name,fun s – > s.Name)
内容总结
以上是互联网集市为您收集整理的将表达式和lambdas参数传递给F#中的C#扩展方法全部内容,希望文章能够帮你解决将表达式和lambdas参数传递给F#中的C#扩展方法所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。