C# 如何作为委托重写Linq扩展方法?
我问这个问题, 答案很好,但我不明白它为什么有效。我不明白,因为我不知道怎么读 作为代表,我如何重写?我想看函数,而不是lambda,这样我才能可视化它C# 如何作为委托重写Linq扩展方法?,c#,.net,linq,lambda,delegates,C#,.net,Linq,Lambda,Delegates,我问这个问题, 答案很好,但我不明白它为什么有效。我不明白,因为我不知道怎么读 作为代表,我如何重写?我想看函数,而不是lambda,这样我才能可视化它 var groupedPosts = userposts.GroupBy(f => f.UserId, posts => posts, (k, v) => new User() { UserId = k, Name = v.FirstOrDefault().Name,
var groupedPosts = userposts.GroupBy(f => f.UserId, posts => posts, (k, v) =>
new User()
{
UserId = k,
Name = v.FirstOrDefault().Name,
Posts = v.Select(f => new Post() { Id = f.Id,
Title= f.Title,
Content = f.Content})
}).ToList();
我最感兴趣的是这一部分:
f => f.UserId, posts => posts,
以及它与
(k, v)
在那之后,我相信我能得到它。你的意思是你想看到这样的东西:
public static int fId(Foo f)
{
return f.Id;
}
public static Foo fPosts(Foo f)
{
return f;
}
public static User fSelect(int k, IEnumerable<Foo> v )
{
return new User()
{
UserId = k,
Name = v.FirstOrDefault().Name,
Posts = v.Select(f => new Post()
{
Id = f.Id,
Title = f.Title,
Content = f.Content
})
};
}
var groupedPosts = userposts.GroupBy(fId, fPosts, fSelect);
publicstaticintfid(foof)
{
返回f.Id;
}
公共静态Foo fPosts(Foo f)
{
返回f;
}
公共静态用户fSelect(int k,IEnumerable v)
{
返回新用户()
{
UserId=k,
Name=v.FirstOrDefault().Name,
Posts=v.Select(f=>newpost()
{
Id=f.Id,
Title=f.Title,
内容=f.内容
})
};
}
var groupedPosts=userposts.GroupBy(fId、fPosts、fSelect);
重要提示:fId返回
int
。和fPosts返回Foo
。因此,fSelect的参数是int
和IEnumerable
GroupBy是一种扩展方法,其中包含多个重载。
示例中使用的重载具有以下读数
第一个参数(f=>f.UserId
)是一个所谓的键选择器-这将确定每个组的键
第二个参数(posts=>posts
)是值选择器-这将确定组中包含的值类型
第三个参数((k,v)
)被称为结果选择器,它在实现组之前为您提供了一个额外的步骤。这可以访问键(UserId
)作为第一个参数和集合值(UserId
)这使您能够随意更改/过滤/投影结果
例如,如果省略了第三个参数,那么结果将是组,其中键是用户ID
,组中的值是Posts
,但是使用第三个参数,我们现在可以访问用户ID(键)和Posts(值)并将它们投射到一个新类型中-用户
将您的答案读为:
按用户ID对用户帖子进行分组;对于每个组,获取该id的所有帖子;现在,对于每个组,获取用户ID及其所有帖子并执行。。。和他们在一起
解释
表达式f=>f.UserId
,posts=>posts
看起来就像是函数。但事实并非如此。是的,但是有点不。。。嗯,这让人困惑。他们所做的是填补一些C语言中不存在的语法
关键是,如何与GroupBy()方法进行通信:
- 您想要分组的内容:密钥
- 您希望在每个组中拥有的内容:元素
- 您希望对每个组中的元素进行什么(如果有)进一步处理。(第三个项目很好,但这正是框架给我们的)
如果C#能够支持以下语法可能会更好:
var groupedPosts = userposts.GroupBy( UserId, this, (k, v) => {...});
但你可以马上看到,这是无法编译的。您必须向编译器解释,UserId
表示该名称的UserPost
的属性,并且this
的作用域依次为每个UserPost。在泛型和lambdas之前,.net通常通过使用字符串作为字段名来解决这类问题:
var groupedPosts = userposts.GroupBy( "UserId", "", (k, v) => {...});
然后必须进行一些运行时反射,才能将该字符串转换为propertyname,然后获取一个值,从而认识到“”表示整个UserPost
但在C#中,我们喜欢强打字。lambda提供了一种可爱但不明显的方式,可以用强类型的方式“命名”属性:
f=> f.UserId
看到了吗?与其说是函数,不如说是命名属性:“我想要每个userpost的UserId”
同样,您可以“命名”整个实体:
f => f // means exactly the same as posts=>posts
(函数x=>x
在计算机科学中称为身份函数)。这就是为什么很难“形象化”代表的原因。lambda被用作一种简洁、强类型的方法来标识字段或属性
[如果这是非常清楚的,现在让我收回'it's not a function'语句。它是一个函数。假设您希望按名称分组,而不是按用户名分组,并且希望分组不区分大小写。然后您可以使用:
f=> f.Name.ToUpper()
因此,作为一个函数不仅仅是获得强类型的一种方式,它还提供了更强大的选项。您也可以在SQL中这样做。
]
最后一点:
(k, v) => {....}
然后读作“对于每个userId&以及该userId的一组帖子,用它们做”。请注意,名称k&v是任意参数名称,在这里没有多大帮助。我可能会使用:
(userid, postsforuserid) => {...}
把这一切放在一起,你会读到
userposts.GroupBy(
userpost => userpost.UserId,
userpost => userpost,
(userid, postsforuserid) => {...})
大声说:
按用户ID对用户帖子进行分组;对于每个组,获取该id的所有帖子;现在,对于每个组,获取用户ID及其所有帖子并执行。。。和他们在一起
-----------------------------------
因此,你看,看到代理没有多大帮助:
void Main()
{
Del k = delegate (UserPost post) { return post.UserId; };
Del v = delegate (UserPost post) { return post; };
}
class UserId { }
class UserPost { public UserId UserId { get; set; } }
谢谢请问它是哪一种?我说不出来。这是Foo userposts?是的,userposts是Foo的集合。我建议将您的问题重命名为“我应该如何阅读GroupBy和其他Linq方法中的lambdas?”