繁体   English   中英

如何将Linq扩展方法重写为委托?

[英]How can I rewrite Linq Extension Methods as delegates?

我问了这个问题, 如何使用Dapper和多重映射按特定顺序返回一对多记录?

答案是肯定的,但我不明白为什么会起作用。 我不懂,因为我不知道该怎么读。

如何将其重写为代表? 我只想查看函数而不是lambda,这样我就可以看到它。

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);

重要的是:fId返回int fPosts返回Foo 因此,fSelect的参数为intIEnumerable<Foo>

GroupBy是一种扩展方法, 这里有一些重载。 您的示例使用的重载具有以下内容。

第一个参数( f => f.UserId是所谓的键选择器-这将确定每个组的键。

第二个参数( posts => posts )是值选择器-这将确定组中将包含哪种类型的值

第三个参数( (k, v)称为结果选择器,使您在实现该组之前可以再执行一步。 这样,您可以访问UserId )作为第一个参数和一个集合值 (该值将包含在组中UserId所有Posts ),这使您能够随意更改/过滤/投影结果。

因此,例如,如果省略了第三个参数,那么结果将是group,其中键是UserId ,而Groups中的值是Posts ,但是有了第三个参数,我们现在可以访问UserId(键)和Posts(值)并将其投影到新的类型User

阅读答案为:

按UserId分组用户帖子; 对于每个群组,请获取该ID的所有帖子; 现在,对于每个组,获取userId及其所有帖子,并对其进行处理。

说明

表达式f => f.UserIdposts => 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) => {...});

然后必须进行一些运行时反射,才能将该字符串转换为属性名称,然后获取一个值,并意识到“”表示整个UserPost

但是在C#中,我们喜欢强类型。 而且,lambda提供了一种可爱但并非立即显而易见的方式来以强类型方式“命名”属性:

f=> f.UserId

你看? 阅读此书不只是作为一个函数,而是为该属性命名:“我想要每个userpost的UserId”

同样,您可以“命名”整个实体:

f => f // means exactly the same as posts=>posts

(函数x=>x在计算机科学中称为身份函数)。 这就是为什么很难“可视化”代表的原因。 lambda被用作标识字段或属性的简洁, 强类型的方式。

[如果很清楚,让我现在撤消“这不是函数”的声明。 它是一个功能。 假设您要按名称不是UserId分组,而要按名称分组, 并且希望分组不区分大小写。 然后,您可以使用:

f=> f.Name.ToUpper()

因此,成为一个函数不仅是获得强类型的方法,它还提供了更强大的选择。 您也可以在SQL中执行此操作。 ]

最后一点:

(k, v) => {....}

然后,您将其读为“对于每个userId&,以及该userId的帖子集,请对它们进行...”。 请注意,名称k和v是任意参数名称,在这里并不是很有用。 我可能用过:

(userid, postsforuserid) => {...}

汇集全部,您阅读

    userposts.GroupBy(
       userpost  =>  userpost.UserId, 
       userpost  =>  userpost,
       (userid, postsforuserid) => {...})

大声说:

按UserId分组用户帖子; 对于每个群组,请获取该ID的所有帖子; 现在,对于每个组,获取userId及其所有帖子,并对其进行...

————————————————————————————————————

因此,您看到,看到委托并没有太大帮助:

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; } }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM