gpt4 book ai didi

c# - 这个 C# 扩展方法是否不纯,如果是,代码是否错误?

转载 作者:太空狗 更新时间:2023-10-29 23:55:11 25 4
gpt4 key购买 nike

我正在学习一些关于函数编程的知识,我想知道:

1) 如果我的 ForEach扩展方法是纯的?我这样调用它似乎违反了“不要弄乱传入的对象”,对吧?

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach ( var item in source )
action(item);
}


static void Main(string[] args)
{
List<Cat> cats = new List<Cat>()
{
new Cat{ Purring=true,Name="Marcus",Age=10},
new Cat{ Purring=false, Name="Fuzzbucket",Age=25 },
new Cat{ Purring=false, Name="Beanhead",Age=9 },
new Cat{Purring=true,Name="Doofus",Age=3}
};


cats.Where(x=>x.Purring==true).ForEach(x =>
{
Console.WriteLine("{0} is a purring cat... purr!", x.Name);
});

// *************************************************
// Does this code make the extension method impure?
// *************************************************
cats.Where(x => x.Purring == false).ForEach(x =>
{
x.Purring = true; // purr,baby
});

// all the cats now purr
cats.Where(x=>x.Purring==true).ForEach(x =>
{
Console.WriteLine("{0} is a purring cat... purr!", x.Name);
});
}

public class Cat {
public bool Purring;
public string Name;
public int Age;
}

2) 如果是不纯的,是不好的代码吗?我个人认为它使代码看起来比旧的 foreach ( var item in items) { blah; } 更干净。 , 但我担心因为它可能不纯,所以会弄得一团糟。

3) 如果返回 IEnumerable<T> 是否是错误代码而不是 void ?我会说只要它是不纯的,是的,它会是非常糟糕的代码,因为它会鼓励链接一些会修改链的东西。例如,这是错误的代码吗?

// possibly bad extension
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach ( var item in source )
action(item);

return source;

}

最佳答案

不纯并不一定意味着糟糕的代码。许多人发现使用副作用来解决问题既简单又有用。关键是首先要知道如何以纯粹的方式做到这一点,这样你就会知道什么时候不纯是合适的:)。

.NET 在类型系统中没有纯粹的概念,因此接受任意委托(delegate)的“纯粹”方法总是不纯粹的,这取决于它的调用方式。例如,“Where”,又名“filter”,通常被认为是一个纯函数,因为它不修改其参数或修改全局状态。

但是,没有什么可以阻止您将此类代码放入 Where 的参数中。例如:

things.Where(x => { Console.WriteLine("um?"); 
return true; })
.Count();

所以这绝对是对 Where 的不纯用法。 Enumerables 可以在迭代时做任何他们想做的事。

您的代码不好吗? 不。使用 foreach 循环同样“不纯”——您仍在修改源对象。我一直都这样写代码。将一些选择、过滤器等链接在一起,然后对其执行 ForEach 以调用一些工作。你是对的,它更干净,更容易。

示例:ObservableCollection。由于某种原因,它没有 AddRange 方法。那么,如果我想向其中添加一堆东西,我该怎么办?

foreach(var x in things.Where(y => y.Foo > 0)) { collection.Add(x)); } 

things.Where(x => x.Foo > 0).ForEach(collection.Add);

我更喜欢第二个。至少,我不认为它比第一种方式更糟糕。

什么时候是坏代码?当它在意想不到的地方产生副作用代码时。这是我使用 Where 的第一个示例的情况。即便如此,有时范围非常有限且用法很明确。

链接 ForEach

我已经编写了执行类似操作的代码。为了避免混淆,我会给它起另一个名字。主要的困惑是“这是立即评估还是惰性评估?”。 ForEach 意味着它将立即执行一个循环。但是返回 IEnumerable 的东西意味着将根据需要处理这些项目。所以我建议给它起另一个名字(“Process”、“ModifySeq”、“OnEach”……类似的名字),并让它变得懒惰:

public static IEnumerable<T> OnEach(this IEnumerable<T> src, Action<T> f) {
foreach(var x in src) {
f(x);
yield return x;
}
}

关于c# - 这个 C# 扩展方法是否不纯,如果是,代码是否错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/693628/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com