我一直在关注this F# ROP article,并决定尝试在C#中重现它,主要是看是否可以。对于这个问题的长度,我们深表歉意,但是,如果您熟悉ROP,将很容易理解。他以F#歧视工会开始。 type Result<'TSuccess, 'TFailure> = | Success of 'TSuccess | Failure of 'TFailure...我将其翻译为抽象的RopValue类和两个具体的实现(请注意,我已将类名称更改为我更了解的名称)...public abstract class RopValue<TSuccess, TFailure> { public static RopValue<TSuccess, TFailure> Create<TSuccess, TFailure>(TSuccess input) { return new Success<TSuccess, TFailure>(input); }}public class Success<TSuccess, TFailure> : RopValue<TSuccess, TFailure> { public Success(TSuccess value) { Value = value; } public TSuccess Value { get; set; }}public class Failure<TSuccess, TFailure> : RopValue<TSuccess, TFailure> { public Failure(TFailure value) { Value = value; } public TFailure Value { get; set; }}我添加了一个静态Create方法,使您可以从TSuccess对象创建RopValue,该对象将被输入第一个验证函数。然后,我开始编写绑定(bind)函数。 F#版本如下... let bind switchFunction twoTrackInput = match twoTrackInput with | Success s -> switchFunction s | Failure f -> Failure f...与C#等效语言相比,这真是让人难以理解!我不知道是否有更简单的方法可以编写此代码,但这是我想出的...public static RopValue<TSuccess, TFailure> Bind<TSuccess, TFailure>(this RopValue<TSuccess, TFailure> input, Func<RopValue<TSuccess, TFailure>, RopValue<TSuccess, TFailure>> switchFunction) { if (input is Success<TSuccess, TFailure>) { return switchFunction(input); } return input;}请注意,我将其编写为扩展功能,因为它使我能够以更实用的方式使用它。考虑到他验证一个人的用例,然后我编写了一个Person类。public class Person { public string Name { get; set; } public string Email { get; set; } public int Age { get; set; }}...并编写了我的第一个验证功能...public static RopValue<Person, string> CheckName(RopValue<Person, string> res) { if (res.IsSuccess()) { Person person = ((Success<Person, string>)res).Value; if (string.IsNullOrWhiteSpace(person.Name)) { return new Failure<Person, string>("No name"); } return res; } return res;}通过对电子邮件和年龄的几个类似的验证,我可以编写一个总体验证函数,如下所示...private static RopValue<Person, string> Validate(Person person) { return RopValue<Person, string> .Create<Person, string>(person) .Bind(CheckName) .Bind(CheckEmail) .Bind(CheckAge);}这工作正常,并使我能够执行以下操作...Person jim = new Person {Name = "Jim", Email = "", Age = 16};RopValue<Person, string> jimChk = Validate(jim);Debug.WriteLine("Jim returned: " + (jimChk.IsSuccess() ? "Success" : "Failure"));但是,我的执行方式存在一些问题。首先,验证功能要求您传入RopValue,检查其是否成功,如果成功,请拉出Person并进行验证。如果失败,则将其退回。相比之下,他的验证函数采用(相当于)一个Person,并返回(等于一个Result)一个RopValue ... let validateNameNotBlank person = if person.Name = "" then Failure "Name must not be blank" else Success person这要简单得多,但是我无法确定如何在C#中执行此操作。另一个问题是,我们以Success 开始验证链,因此第一个验证函数将始终从“if”块返回某些内容;如果验证失败,则返回Failure ;如果过去则返回Success 支票。如果一个函数返回Failure ,那么验证链中的下一个函数将永远不会被调用,因此事实证明我们知道这些方法永远不会传递给Failure 。因此,这些功能中的每个功能都无法到达最后一行(除非您手动创建了Failure 并在开始时将其传递给它,这很奇怪,但那毫无意义)。然后,他创建了一个切换运算符(> =>)来连接验证功能。我尝试这样做,但无法正常工作。为了链接对函数的连续调用,似乎我必须在Func 上具有扩展方法,我认为您不能这样做。我到此为止...public static RopValue<TSuccess, TFailure> Switch<TSuccess, TFailure>(this Func<TSuccess, RopValue<TSuccess, TFailure>> switch1, Func<TSuccess, RopValue<TSuccess, TFailure>> switch2, TSuccess input) { RopValue<TSuccess, TFailure> res1 = switch1(input); if (res1.IsSuccess()) { return switch2(((Success<TSuccess, TFailure>)res1).Value); } return new Failure<TSuccess, TFailure>(((Failure<TSuccess, TFailure>)res1).Value);}...但是无法弄清楚如何使用它。因此,谁能解释我将如何编写Bind函数,以便它可以使用Person并返回RopValue(就像他的行为一样)?另外,我该如何编写一个switch函数来连接简单的验证函数呢?欢迎对我的代码进行任何其他注释。我不确定它是否可以像它一样整洁和简单。 最佳答案 您的Bind函数的类型错误,应为:public static RopValue<TOut, TFailure> Bind<TSuccess, TFailure, TOut>(this RopValue<TSuccess, TFailure> input, Func<TSuccess, RopValue<TOut, TFailure>> switchFunction) { if (input is Success<TSuccess, TFailure>) { return switchFunction(((Success<TSuccess, TFailure>)input).Value); } return new Failure<TOut, TFailure>(((Failure<TSuccess, TFailure>)input).Value);}传递给Func的实现的Bind参数采用RopValue<TSuccess, TFailure>参数,而不仅仅是TSuccess。这意味着函数需要在输入上重复Bind方法应该为您执行的匹配。由于类型参数的数量,这可能有点笨拙,因此您可以将其移至基类:public abstract RopValue<TOut, TFailure> Bind<TOut>(Func<TSuccess, RopValue<TOut, TFailure> f);public class Success<TSuccess, TFailure> : RopValue<TSuccess, TFailure> { public override RopValue<TOut, TFailure> Bind<TOut>(Func<TSuccess, RopValue<TOut, TFailure> f) { return f(this.Value); }}public class Failure<TSuccess, TFailure> : RopValue<TSuccess, TFailure> { public override RopValue<TOut, TFailure> Bind<TOut>(Func<TSuccess, RopValue<TOut, TFailure> f) { return new Failure<TOut, TFailure>(this.Value); }}然后,您可以避免在链的开头创建虚拟值:private static RopValue<Person, string> Validate(Person person) { return CheckName(person) .Bind(CheckEmail) .Bind(CheckAge);}关于c# - C#中的面向铁路的编程-如何编写开关功能?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35929508/ 10-11 07:02