2017-01-28 1 views
1

Я задал этот вопрос, How do I return one-to-many records in a specific order with Dapper and multi-mapping?Как можно переписать Linq Extension Methods в качестве делегатов?

и ответ велик, но я не понимаю, почему он работает. Я не понимаю, потому что не знаю, как это прочитать.

Как я могу переписать это как делегаты? Я хочу видеть функции вместо лямбда, только чтобы я мог ее визуализировать.

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) 

После того, что я могу получить его, я считаю.

+0

Я соблазн предложить переименовать ваш вопрос, «Как я должен читать лямбда в GroupBy и других методах Linq? " –

ответ

1

Читать ответ как:

Группа userposts по UserId; для каждой группы, возьмите все посты для этого id; теперь для каждой группы, возьмите userId и все его сообщения и сделайте ... с ними.

Объяснение

Выражение f => f.UserId, posts => posts выглядят, как будто они функция. Но это не так. Ну, они есть, но вроде не ... ну, это сбивает с толку. То, что они делают, заполняется для некоторого синтаксиса, который не может существовать на языке C#.

Дело в том, как вы можете связаться с GroupBy() способом:

  • Что вы хотите сгруппировать по: ключевой
  • То, что вы хотите иметь в каждой группе: Элементы
  • Что (если таковые имеются) дальнейшей обработки, которую вы хотите сделать с элементами в каждой группе. (Это третья пуля является хорошим бы иметь, но это то, что основа дает нам)

Было бы хорошо, если бы C# может поддерживать следующий синтаксис:

var groupedPosts = userposts.GroupBy(UserId, this, (k, v) => {...}); 

но вы можете сразу увидеть которые никогда не скомпилировались. Вы должны объяснить компилятору, что UserId означает свойство UserPost этого имени и что this в свою очередь относится к каждому пользовательскому адресу. Перед дженериков & лямбды, .net часто решаются такого рода вещи с помощью строки для имя_поля:

var groupedPosts = userposts.GroupBy("UserId", "", (k, v) => {...}); 

, а затем там должен быть какой-то во время выполнения отражения, чтобы превратить эту строку в PROPERTYNAME & затем получить значение, & понимать, что "" означает все UserPost

Но в C# мы любим строго типизировать. И лямбда дает симпатичный но-не-сразу-очевидный способ «имя» свойство в сильном типизированного образом:

f=> f.UserId 

вы видите? Прочитайте это не так много, как функции, но, как именование свойство: «Я хочу UserId каждого userpost»

Аналогично, вы можете «имя» в единое целое:

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

(Функция x=>x является называемой тождественной функцией в информатике). И поэтому трудно «визуализировать» делегата. Лямбда используется в качестве аккуратного, точного определения типа поля или свойства .

[Если это кристально чисто, позвольте мне теперь отменить инструкцию «это не функция». Это функция. Предположим, вы хотите сгруппировать, а не UserId, но по имени, и вы хотите, чтобы группа была нечувствительной к регистру. Тогда вы могли бы использовать:

f=> f.Name.ToUpper() 

Так быть функцией не только способ получить сильную типизацию, это также дает более мощные варианты. Вы можете сделать это и в SQL. ]

Конечный бит:

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

вы читаться "для каждого USERID & и набор сообщений для этого USERID, сделать ... с ними". Обратите внимание, что имена k & v являются произвольными именами параметров и здесь не так полезны. Я мог бы использовать:

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

Собираем все вместе, вы читали

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

вслух как:

Группа userposts от 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; } } 
2

Вы имеете в виду вы хотите увидеть что-то вроде этого:

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 составляют int и IEnumerable<Foo>.

+0

Является ли пользовательским адресом Foo? – johnny

+1

Да, userposts - коллекция Foo –

2

GroupBy - это метод расширения с несколькими перегрузками here подробнее об этом. Перегрузка, которая используется в вашем примере, имеет следующее чтение.

Первый аргумент (f => f.UserId) - так называемый селектор ключей - это определит ключ для каждой группы.

Второй аргумент (posts => posts) выбирает значение - это determ какой тип значений будет содержаться в группах

Третий аргумент ((k, v)) называется селектором результат дает один дополнительный шаг до того, как группа будет реализована. Это вы можете получить доступ к ключу (UserId) в качестве первого аргумента и коллекции дорожит (значения, которые будут содержаться в группе - все Posts для UserId) это дает вам возможность изменить/фильтр/проекта результата Aditionally.

Так, например, если третий аргумент опущен, то результат будет группы, где ключевым является UserId и значение в группах является Posts, но с третьим аргументом теперь мы можем получить доступ к UserId (ключ) и сообщения (значения) и проецировать их в новый тип - User.

+0

Спасибо. Могу ли я спросить, какая перегрузка? Я не могу сказать. – johnny

+1

Этот https://msdn.microsoft.com/en-us/library/bb534493(v=vs.110).aspx –