C# csharp与面向铁路的程序设计
从这个惊人的课程: 我正在尝试应用领域驱动设计、功能原理和面向铁路的编程方法 有人能帮我把下面的代码精简一下吗 我知道我需要创建一些T扩展方法的结果,我尝试过,但无法让它们工作 伪代码所做的是C# csharp与面向铁路的程序设计,c#,functional-programming,C#,Functional Programming,从这个惊人的课程: 我正在尝试应用领域驱动设计、功能原理和面向铁路的编程方法 有人能帮我把下面的代码精简一下吗 我知道我需要创建一些T扩展方法的结果,我尝试过,但无法让它们工作 伪代码所做的是 创建电子邮件值对象->电子邮件。创建 创建和EmailAddress实体->EmailAddress.Create 结果存储在T变量emailAddress的结果中 (我们在点击数据库进行更新操作之前执行此操作,如果获得无效的电子邮件地址,则根本没有意义点击数据库) (由于以后需要使用可变的emailAd
var emailAddress = Email.Create("jamesbond@gmail.com")
.OnSuccess(email => EmailAddress.Create(email, default));
var playerResult = await emailAddress.OnSuccess(e => repository.GetAsync("336978e9-837a-4e8d-6b82-08d6347fe6b6")).ToResult(""));
var wasAdded = playerResult.OnSuccess(p => p.AddEmailAddress(emailAddress.Value));
var wasSaved = await wasAdded.OnSuccess(a => unitOfWork.SaveChangesAsync());
var message = wasSaved
.Ensure(r => r > 0, "No record were saved")
.OnBoth(result => result.IsSuccess ? "Ok" : result.Error);
下面是方法的签名
Email.Create -> public static Result<Email> Create(string email)
EmailAddress.Create -> public static Result<EmailAddress> Create(Email mailAddress, string mailAddressInstructions)
GetAsync -> public Task<Maybe<Player>> GetAsync(string id)
AddEmailAddress -> public Result<bool> AddEmailAddress(EmailAddress emailAddress)
SaveChangesAsync -> public async Task<int> SaveChangesAsync()
Email.Create->公共静态结果创建(字符串电子邮件)
EmailAddress.Create->公共静态结果创建(emailmaildress,stringmaildAddressInstructions)
GetAsync->公共任务GetAsync(字符串id)
AddEmailAddress->公共结果AddEmailAddress(EmailAddress EmailAddress)
SaveChangesAsync->公共异步任务SaveChangesAsync()
我执行了一些单元测试,代码正在运行,但就您所见,它还远未面向铁路
提前感谢。就我个人而言,我更喜欢使用局部变量;我认为它更易于维护。在处理工作单元等非功能性设计时尤其如此。但是,您想要做的是使用功能性编程结构 要删除局部变量,需要使用两种方法。首先,monad需要一个
bind
;这使您可以展开多个值,然后将它们映射到一个新值。第二种方法是元组
我发现让我的域类型本身对函数类型一无所知是很有用的。所以只有常规方法之类的,不返回结果类型:
private static Task<Player> RepositoryGetAsync(string id) => Task.FromResult(new Player());
private static Task<int> RepositorySaveChangesAsync() => Task.FromResult(0);
public sealed class Player
{
public bool AddEmailAddress(EmailAddress address) => true;
}
public sealed class Email
{
public Email(string address) => Address = address ?? throw new ArgumentNullException(nameof(address));
public string Address { get; }
}
public sealed class EmailAddress
{
public static EmailAddress Create(Email address, int value) => new EmailAddress();
}
如果我们开始使用元组,那么我们可以组合几个变量。语法有点笨拙(例如,解构lambda参数),但这是可行的:
static async Task Main(string[] args)
{
var emailAddressAndPlayerResult = await Try.Create(() => new Email("jamesbond@gmail.com"))
.Map(email => EmailAddress.Create(email, default))
.Map(async emailAddress => (emailAddress, await RepositoryGetAsync("336978e9-837a-4e8d-6b82-08d6347fe6b6")));
var wasAdded = emailAddressAndPlayerResult.Map(((EmailAddress Address, Player Player) v) => v.Player.AddEmailAddress(v.Address));
var wasSaved = await wasAdded.Map(_ => RepositorySaveChangesAsync());
if (wasSaved.Value == 0)
throw new Exception("No records were saved");
}
一旦我们在混合中有了元组,其余的变量就可以很好地折叠起来。剩下的唯一尴尬的部分是await
通常需要括号。例如,此代码与上面的代码相同:
static async Task Main(string[] args)
{
var wasAdded =
(
await Try.Create(() => new Email("jamesbond@gmail.com"))
.Map(email => EmailAddress.Create(email, default))
.Map(async emailAddress => (emailAddress, await RepositoryGetAsync("336978e9-837a-4e8d-6b82-08d6347fe6b6")))
)
.Map(((EmailAddress Address, Player Player) v) => v.Player.AddEmailAddress(v.Address));
var wasSaved = await wasAdded.Map(_ => RepositorySaveChangesAsync());
if (wasSaved.Value == 0)
throw new Exception("No records were saved");
}
现在,当我们组合这些变量时,您可以看到await
表达式是如何在道路上产生“颠簸”的。丑陋但可行。要删除最后一个变量:
static async Task Main(string[] args)
{
var wasSaved =
await
(
await Try.Create(() => new Email("jamesbond@gmail.com"))
.Map(email => EmailAddress.Create(email, default))
.Map(async emailAddress => (emailAddress, await RepositoryGetAsync("336978e9-837a-4e8d-6b82-08d6347fe6b6")))
)
.Map(((EmailAddress Address, Player Player) v) => v.Player.AddEmailAddress(v.Address))
.Map(_ => RepositorySaveChangesAsync());
if (wasSaved.Value == 0)
throw new Exception("No records were saved");
}
重申一下我在一开始所说的,这是可能的,但在我看来,这很难看,而且不易维护。底线是C#是一种命令式语言,而不是函数式语言。在部分代码中采用函数式语言的某些方面可以使它更优雅;试图强制所有代码都具有完全的功能性是不可能的无法维护的秘诀。感谢您的回复。我会尝试更好地理解您的建议和发布的代码。链接到结果和可能的定义:
static async Task Main(string[] args)
{
var wasSaved =
await
(
await Try.Create(() => new Email("jamesbond@gmail.com"))
.Map(email => EmailAddress.Create(email, default))
.Map(async emailAddress => (emailAddress, await RepositoryGetAsync("336978e9-837a-4e8d-6b82-08d6347fe6b6")))
)
.Map(((EmailAddress Address, Player Player) v) => v.Player.AddEmailAddress(v.Address))
.Map(_ => RepositorySaveChangesAsync());
if (wasSaved.Value == 0)
throw new Exception("No records were saved");
}