我正在学习C#,而且我发现LINQ非常有趣。然而,让我困惑的是,我想不出一个场景,在这种情况下使用LINQ会帮助我解决问题,因为在代码中复制LINQ的功能真的不难。
你有任何个人经验或建议想要分享吗?
谢谢!
我发现每当我需要填充容器时,我就会使用LINQ,而不是以前常用的循环。我在ORM方面使用LINQ to SQL,在其他方面也广泛使用LINQ。
这是我为Active Directory助手类编写的一个小片段,它可以查找特定用户是否在特定组中。请注意使用Any()方法迭代用户的授权组,直到找到一个具有匹配SID的组。与替代方案相比,代码更加简洁。
private bool IsInGroup( GroupPrincipal group, UserPrincipal user )
{
if (group == null || group.Sid == null)
{
return false;
}
return user.GetAuthorizationGroups()
.Any( g => g.Sid != null && g.Sid.CompareTo( group.Sid ) == 0 );
}
替代方案:
private bool IsInGroup( GroupPrincipal group, UserPrincipal user )
{
if (group == null || group.Sid == null)
{
return false;
}
bool inGroup = false;
foreach (var g in user.GetAuthorizationGroups())
{
if ( g => g.Sid != null && g.Sid.CompareTo( group.Sid ) == 0 )
{
inGroup = true;
break;
}
}
return inGroup;
}
或者private bool IsInGroup( GroupPrincipal group, UserPrincipal user )
{
if (group == null || group.Sid == null)
{
return false;
}
foreach (var g in user.GetAuthorizationGroups())
{
if ( g => g.Sid != null && g.Sid.CompareTo( group.Sid ) == 0 )
{
return true;
}
}
return false;
}
以下是一段代码片段,它对存储库进行搜索,并将前10个匹配的业务对象按顺序转换为视图特定的模型(Distance
是匹配模型的唯一id与uniqueID参数之间的Levenshtein编辑距离)。
model.Results = this.Repository.FindGuestByUniqueID( uniqueID, withExpired )
.OrderBy( g => g.Distance )
.Take( 10 )
.ToList()
.Select( g => new GuestGridModel( g ) );
true;
。 - Idan K这取决于您指的是哪种类型的linq。
如果是linq-to-sql,那么它是一个ORM,具有与使用任何其他ORM相同的所有优点。我很少使用它,不能说更多。
如果是linq-to-objects,那么您实际上在谈论其他东西的集合:扩展方法,惰性迭代器和查询理解语法。这是介绍函数式编程世界的一种方式。我对查询理解语法没有太多用处,但对于其他部分,我可以通过以下示例进行最佳演示。
假设您想要逐行读取文件。对于每一行,您都想检查它是否符合某些条件,将其中某些行的一部分转换为整数,并将前10个在某个范围内的这些整数求和。这里是旧的方法:
int SumXValues(string filename)
{
string line;
int sum = 0;
int count = 0;
using (var rdr = new StreamReader(filename))
{
while ( (line = rdr.ReadLine()) != null && count < 10)
{
int val;
if (int.TryParse(line.Substring(3,3))
{
if (val > 4 && val < 25)
{
sum += val;
count ++;
}
}
}
}
return sum;
}
这是新的方法:
IEnumerable<string> ReadLines(string filename)
{
string line;
using (var rdr = new StreamReader(filename))
while ( (line = rdr.ReadLine()) != null)
yield return line;
}
int SumXValues(string filename)
{
return ReadLines(filename)
.Select(l => l.Substring(3,3))
.Where(l => int.TryParse(l))
.Select(i => int.Parse(i))
.Where(i => i > 4 && i < 16)
.Take(10)
.Sum(i => i);
}
注意新的代码实际上更短。但为什么它也更 好 呢?至少有4个原因:
当我有一个对象集合,并且我需要查找符合某些条件的项时,我发现使用LINQ非常有用。简单的例子是,在一组形状中搜索所有圆形的形状。
var circles =
from s in allShapes
where s.Type == ShapeTypes.Circle
select s;
我承认我本可以写一个带有一些代码的循环,但我发现这段代码更短、更容易编写,更容易阅读和理解。
LINQ也可以用于数据库,但我实际上并不经常使用它。我想每个人都有自己的偏好吧。
这本书 Essential LINQ 提供了一个很好的段落概述LINQ的好处:
LINQ不仅仅是为语言增加新特性。它将一种声明式编程风格引入到C#语言中。声明式编程模型允许开发人员编写能够简洁地捕捉其意图的代码,而无需担心事件发生的顺序或其精确实现。它允许开发人员陈述他们想要做什么,而不是如何去做。
你说得对,使用常规C#很难复制这些功能。这就是所谓的语法糖,只是为了方便。你知道自动属性吗?它们允许你编写 public class User { public int Id { get; set; } }
这在“常规”C#代码中非常容易复制。即使如此,自动属性仍然很棒 ;)
过滤和排序几乎是LINQ的核心。假设你有一个用户列表,称为users
,你想找到今天登录的用户,并按最近登录的顺序显示它们。在使用LINQ之前,你可能会创建一个新列表,根据原始列表进行迭代,添加符合条件的内容,然后实现某种IComparable
。现在你可以这样做:
users = users.Where(u => u.LastLoggedIn.Date = DateTime.Today)
.OrderBy(u => u.LastLoggedIn).ToList();
方便 =)
我经常使用LINQ to DataSet来处理DataTable。DataTable是一种通用的数据存储方式,我经常将从加载的CSV文件中获取的值存储在其中。使用LINQ进行查询或连接数据比使用"brute-force"-ing循环更易读和舒适。
foreach (var person in people.OrderBy(p => p.Company)
.ThenBy(p => p.LastName)
.ThenBy(p => p.FirstName)) {
...
}
我想可以使用 Arrays.Sort
,创建一个委托来按正确的顺序检查字段(从写入的反向开始,对吗?),然后只接受它只能在数组上工作的事实。这似乎会更加冗长,难以维护和不太灵活。
浏览Jon Skeet提供的任何一个Linq问题答案,您将看到Linq的多功能和实用性。
有人提到LINQ是一种声明式编程风格,我想进一步扩展一下。
我使用LINQ的一种方式是编写测试用例代码。测试代码必须简单明了,并且尽可能接近“显然正确”,否则它将会出现与被测试代码一样多的错误。对于我正在测试的一个特定功能,我编写了一小组集合推导式,准确地描述了该功能的工作方式。由于LINQ的存在,将这些推导式转换为代码变得非常容易:
A = all items
B = [x in A: x.Type = selectedtype, x.Source = "sourceA"]
C = [x in A: x.Source = "sourceB"]
D = B union C
在代码中:
IEnumerable<MyClass> SetB(IEnumerable<MyClass> allItems, MyType type)
{
var result = from item in allItems
where item.Type == type && item.Source == "sourceA"
select item;
return result;
}
IEnumerable<MyClass> SetC(IEnumerable<MyClass> allItems)
{
var result = from item in allItems
where item.Source == "sourceB"
select item;
return result;
}
IEnumerable<MyClass> SetD(IEnumerable<MyClass> allItems, MyType type)
{
var setB = SetB(allItems, type);
var setC = SetC(allItems);
return setB.Union(setC);
}
虽然比数学表达式冗长得多,但与命令式代码相比,它更简单、更容易被称为“显然正确”。LINQ 代码像数学一样是声明性的。翻译较少,更接近规范。当适当使用时,LINQ 几乎是一种“做我想要的”语言。
请注意,我不会以这种方式编写实际代码。性能对于测试代码来说并不是必需的,但对于真正的代码来说却是必需的,因此真正的代码仍然需要是 SQL 存储过程。
foreach
很有趣。但困扰我的是,我无法想象在什么情况下使用foreach
会极大地帮助我,因为在代码中复制foreach
的功能并不难。 - user7116