C# netcore3.1 Linq:是否建议使用 Select() 调用"impure"函数?



给定"(即产生副作用的)函数,如:

public MyResultClass DoWork(MyEntityClass myEntity)
{
if (myEntity.DateUpdated == default)
myEntity.DateUpdated = DateTime.Now;
MyResultClass result = _dbUtility.InsertOrUpdate(myEntity);
return result;          
}

我敢说,这不是一个纯粹的函数,因为它有副作用——即它修改输入对象(使用不确定的值,不少于!)并对数据库执行插入/更新操作。

然而,对于Linq——它(有争议地)被认为是c#的纯函数子集——下面的代码是合法的,并且可以像"非纯函数"一样工作。背景:

IEnumerable<MyResultClass> = myIEnumerableEntities.Select(entity => DoWork(entity));

表示(1)myObjectDateUpdated属性被修改(如果default),(2)数据库插入/更新成功。

这是否表明Linq不是真正的功能子语言?还是我误解纯函数和函数式编程的概念?(无论如何,我仍然计划使用这种模式,除非有最佳实践理由让我避免使用它;如果有这样的理由,我当然会考虑那些)。

c#没有明确区分纯函数和非纯操作。因此,对于像SelectSelectMany这样的高阶函数,您可以将非纯操作作为参数传递。语言中没有任何东西可以阻止这一点。因此,LINQ不能被认为是c#的一个严格的功能子集。

c#查询语法是基于函子和单子的概念,这是在严格的函数式语言Haskell中首次普及的。Haskell还使用一个名为IO的特定单子来模拟非纯操作,因此在这种情况下,您可能会认为在SelectMany(单子bind)调用中执行副作用在某种意义上是惯用的。但是,要使用的单子应该是异步单子,而不是List单子。

IEnumerable<T>.Select内部执行副作用被认为是不习惯的。用foreach代替。

在查询末尾添加ToList()。但是记住,标准LINQ查询数据,不修改数据。使用foreach代替。——SvyatoslavDanyliv

LINQ旨在以函数方式使用,但确实存在语义上没有强制要求。c#仍然是必不可少的语言在它的核心,并没有什么可以表达,一个方法或委托没有副作用。你应该避免的原因副作用是,它们使代码的正常运行变得非常困难很难推理,可能会破坏一些东西,如果你首先要查询的是修改,即抑制并行性(这是一个遗憾,因为PLINQ碰巧非常方便)和颠覆的期望读者查询。- - - - - -珀斯便宜

@svyatoslav-danyliv和@jeroen-mostert已经回答了我的问题。谢谢!

相关内容

  • 没有找到相关文章

最新更新