C# 技巧 – 在 List.Find() 谓词中使用委托
如何在 C# 的 List.Find() 谓词中使用委托
如果我们有一种函数式语言(例如 Lisp 或 F#),我们可以轻松管理一个集合或列表。
使用 .NET Framework 2.0,我们可以同样地使用函数式编程来处理 泛型 (探索)。使用 CLR 的此功能,我们可以更轻松地开发、处理和管理我们的数据,尤其是使用 匿名委托。
我想使用的一个例子,也是我开发过程中最常见的例子,是将这些匿名委托用于泛型列表 (List<T>) 的搜索函数 Find()。
我使用谓词来代替每次需要在一个集合中查找元素时都编写 foreach
循环,这样我就能保持代码的简洁性,并且可以专注于更“有趣”的事情。
使用 Predicate 的 Find()
方法的最简单方法包含在此 C# 代码中
public class person
{
public int Anni { get; set; }
public string Nome { get; set; }
public person(int anni, string nome)
{
this.Anni = anni;
this.Nome = nome;
}
}
//I assume I have a non-empty list
List<person> agenda = new List<person>();
/* .. load objects from DataBase .. */
//I create a simple search criteria
string personToBeSearched = "mario";
person mario = agenda.Find(delegate(person p) { return p.Nome == personToBeSearched; });
使用 Lambda 表达式 (探索),该表达式在 .NET Framework 3.5 中引入,代码进一步减少
//I assume I have a non-empty list
List<person> agenda = new List<person>();
/* .. load objects from DataBase .. */
//I create a simple search criteria
string personToBeSearched = "mario";
person mario = agenda.Find(p => p.Nome == personToBeSearched;);
如果您不喜欢看到过于简洁的代码,也可以编写显式谓词
private static bool findTeen(person p)
{
if (p.Anni < 18)
return true;
return false;
}
List<person> BlockBuster_GameOnly = agenda.findAll(findTeen);
我们可以进一步改进代码,不仅将这种方法应用于 Find()
方法,而且也应用于其他用例。实际上,我们可以通过重写 Equals()
方法来扩展表示数据的类,就像在另一个 C# 示例中一样
public class person
{
public int Anni { get; set; }
public string Nome { get; set; }
public person(int anni, string nome)
{
Anni = anni;
Nome = nome;
}
public override bool Equals(object obj)
{
if (obj == null) return false;
person p2 = obj as person;
if ((object)p2 == null) return false;
return (this.Anni == p2.Anni) && (this.Nome == p2.Nome);
//return (this.Anni.Equal(p2.Anni)) && this.Nome.Equal(p2.Nome));
}
public override bool Equals(person p2)
{
if ((object)p2 == null) return false;
return (this.Anni == p2.Anni) && (this.Nome == p2.Nome);
//return (this.Anni.Equal(p2.Anni)) && this.Nome.Equal(p2.Nome));
}
public override int GetHashCode()
{
return this.Anni ^ this.Nome.Length;
}
}
通过这种方式,我们不仅可以基于单个属性进行搜索,还可以搜索特定列表中的“实体”
person Glauco = new person(36, "Glauco");
if (agenda.Find(p => p.Equals(Glauco)) == null)
agenda.Add(Glauco);
正如您从代码中看到的那样,在这些简单的情况下编写 lambda 表达式可能非常直观和容易,但是如果我们有包含非常复杂对象的列表会发生什么呢?例如,一个标识乘用车的 testCrash
的对象,或者一个表示装配线数值控制系统测量的对象,而不是用于检测电站气体厂的数据。这些对象可能非常复杂,代码几乎变得不可读。最好选择显式谓词版本。但是即使在这种情况下,我们也会为每个不同的搜索条件或我们可能服务的任何排序顺序编写一个谓词。
我们通过创建一个“类谓词”来解决这个问题,该谓词允许参数并显示 search
方法。通过这种方式,我们可以大幅减少需要编写的谓词(尽管实际上不可能将我们减少到一个)。我们还看到了针对这种情况的一个简单示例(为了不使这篇文章复杂化),始终用 C# 编写
private class EnvironmentMonitoringResult
{
//...
//...
//...
}
private enum CostructormanagerType
{
gasMetano = 0,
gasButano,
//...
//...
}
private class myPredicate
{
private CostructormanagerType impianto;
private bool dummy;
private string Parametro1;
//...
//...
//...
public myPredicate(CostructormanagerType type)
{
this.impianto = type;
}
public myPredicate(CostructormanagerType type, bool isDummy)
{
this.impianto = type;
this.dummy = isDummy;
}
public bool findTipo1(EnvironmentMonitoringResult risultatoMisurazione)
{
bool findOK = true;
switch (this.impianto)
{
case CostructormanagerType.gasMetano:
findOK &= risultatoMisurazione.isNotturno = this.dummy;
findOK &= risultatoMisurazione.Parametro1 = this.Parametro1;
//...
//altri controlli
break;
case CostructormanagerType.gasButano:
break;
default:
break;
}
//...
//altri controlli
return findOK;
}
public bool findTipo2(EnvironmentMonitoringResult risultatoMisurazione)
{ ... ... }
}
List<EnvironmentMonitoringResult> misurazioniMensili = new List<EnvironmentMonitoringResult>();
myPredicate ricercaCaso1 = new myPredicate(CostructormanagerType.gasButano, false);
//ricercaCaso1.ParametroX = qualcheCosa
EnvironmentMonitoringResult controlloAllarmeNotturno = misurazioniMensili.Find(ricercaCaso1.findTipo1);
//ricercaCaso1.ParametroY = qualcheCosaAltro
//ricercaCaso1.ParametroZ = stoInventando
EnvironmentMonitoringResult controlloCrashZonaAlfaX = misurazioniMensili.Find(ricercaCaso1.findTipo2);
您可以看到,即使是复杂的搜索也可以包含在单个类中,并且可能在单独的层(例如,EnvironmentService
)中实现,该层与任何 interface
或 BusinessLogic
分开。
关注点
就像我们使用匿名委托进行 Find()
方法和 FindAll()
方法一样,我们可以通过实现 IComparable 接口,并使用谓词(或 Lambda 表达式)进行 Sort()
方法。