diff --git a/src/libraries/System.Linq.Queryable/src/System/Linq/Queryable.cs b/src/libraries/System.Linq.Queryable/src/System/Linq/Queryable.cs index 0bfe55333b9f1d..71e7727a586e60 100644 --- a/src/libraries/System.Linq.Queryable/src/System/Linq/Queryable.cs +++ b/src/libraries/System.Linq.Queryable/src/System/Linq/Queryable.cs @@ -178,6 +178,103 @@ private static Expression GetSourceExpression(IEnumerable sour return q != null ? q.Expression : Expression.Constant(source, typeof(IEnumerable)); } + /// + /// Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing an inner join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform an inner join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void JoinEx1() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { magnus, terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.Join(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person.Name, Pet = pet.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName, + /// obj.Pet); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// Hedlund, Magnus - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// */ + /// + /// + /// + /// + /// This method has at least one parameter of type whose type argument is one of the types. + /// For these parameters, you can pass in a lambda expression and it will be compiled to an . + /// + /// + /// The method + /// generates a that represents calling + /// + /// itself as a constructed generic method. + /// It then passes the to the method of the represented by the property of the parameter. + /// + /// + /// The query behavior that occurs as a result of executing an expression tree that represents calling + /// + /// depends on the implementation of the type of the parameter. + /// The expected behavior is that of an inner join. + /// The and functions are used to extract keys from and , respectively. + /// These keys are compared for equality to match elements from each sequence. + /// A pair of elements is stored for each element in that matches an element in . + /// Then the function is invoked to project a result object from each pair of matching elements. + /// + /// [DynamicDependency("Join`4", typeof(Enumerable))] public static IQueryable Join(this IQueryable outer, IEnumerable inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector) { @@ -194,6 +291,105 @@ public static IQueryable Join(this IQuer outer.Expression, GetSourceExpression(inner), Expression.Quote(outerKeySelector), Expression.Quote(innerKeySelector), Expression.Quote(resultSelector))); } + /// + /// Correlates the elements of two sequences based on matching keys. A specified is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// An to hash and compare keys. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing an inner join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform an inner join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void JoinEx1() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { magnus, terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Join the list of Person objects and the list of Pet objects + /// // to create a list of person-pet pairs where each element is + /// // an anonymous type that contains the name of pet and the name + /// // of the person that owns the pet. + /// var query = + /// people.AsQueryable().Join(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person.Name, Pet = pet.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName, + /// obj.Pet); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// Hedlund, Magnus - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// */ + /// + /// + /// + /// + /// This method has at least one parameter of type whose type argument is one of the types. + /// For these parameters, you can pass in a lambda expression and it will be compiled to an . + /// + /// + /// The method + /// generates a that represents calling + /// + /// itself as a constructed generic method. + /// It then passes the to the method of the represented by the property of the parameter. + /// + /// + /// The query behavior that occurs as a result of executing an expression tree that represents calling + /// + /// depends on the implementation of the type of the parameter. + /// The expected behavior is that of an inner join. + /// The and functions are used to extract keys from and , respectively. + /// These keys are compared for equality to match elements from each sequence. + /// A pair of elements is stored for each element in that matches an element in . + /// Then the function is invoked to project a result object from each pair of matching elements. + /// + /// [DynamicDependency("Join`4", typeof(Enumerable))] public static IQueryable Join(this IQueryable outer, IEnumerable inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector, IEqualityComparer? comparer) { @@ -242,6 +438,104 @@ public static IQueryable GroupJoin(this outer.Expression, GetSourceExpression(inner), Expression.Quote(outerKeySelector), Expression.Quote(innerKeySelector), Expression.Quote(resultSelector), Expression.Constant(comparer, typeof(IEqualityComparer)))); } + /// + /// Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing a left outer join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform an inner join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void LeftJoin() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { magnus, terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.AsQueryable().LeftJoin(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person.Name, Pet = pet?.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName, + /// obj.Pet ?? "NONE"); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// Hedlund, Magnus - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// Chapkin, Tom - NONE + /// */ + /// + /// + /// + /// + /// This method has at least one parameter of type whose type argument is one of the types. + /// For these parameters, you can pass in a lambda expression and it will be compiled to an . + /// + /// + /// The method + /// generates a that represents calling + /// + /// itself as a constructed generic method. + /// It then passes the to the method of the represented by the property of the parameter. + /// + /// + /// The query behavior that occurs as a result of executing an expression tree that represents calling + /// + /// depends on the implementation of the type of the parameter. + /// The expected behavior is that of a left outer join. + /// The and functions are used to extract keys from and , respectively. + /// These keys are compared for equality to match elements from each sequence. + /// A pair of elements is stored for each element in that matches an element in , plus a pair for each element in that has no matches in . + /// Then the function is invoked to project a result object from each pair of elements. + /// + /// [DynamicDependency("LeftJoin`4", typeof(Enumerable))] public static IQueryable LeftJoin(this IQueryable outer, IEnumerable inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector) { @@ -258,6 +552,105 @@ public static IQueryable LeftJoin(this I outer.Expression, GetSourceExpression(inner), Expression.Quote(outerKeySelector), Expression.Quote(innerKeySelector), Expression.Quote(resultSelector))); } + /// + /// Correlates the elements of two sequences based on matching keys. A specified is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// An to hash and compare keys. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing a left outer join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform an inner join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void LeftJoin() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { magnus, terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.AsQueryable().LeftJoin(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person.Name, Pet = pet?.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName, + /// obj.Pet ?? "NONE"); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// Hedlund, Magnus - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// Chapkin, Tom - NONE + /// */ + /// + /// + /// + /// + /// This method has at least one parameter of type whose type argument is one of the types. + /// For these parameters, you can pass in a lambda expression and it will be compiled to an . + /// + /// + /// The method + /// generates a that represents calling + /// + /// itself as a constructed generic method. + /// It then passes the to the method of the represented by the property of the parameter. + /// + /// + /// The query behavior that occurs as a result of executing an expression tree that represents calling + /// + /// depends on the implementation of the type of the parameter. + /// The expected behavior is that of a left outer join. + /// The and functions are used to extract keys from and , respectively. + /// These keys are compared for equality to match elements from each sequence. + /// A pair of elements is stored for each element in that matches an element in , plus a pair for each element in that has no matches in . + /// Then the function is invoked to project a result object from each pair of elements. + /// + /// [DynamicDependency("LeftJoin`4", typeof(Enumerable))] public static IQueryable LeftJoin(this IQueryable outer, IEnumerable inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector, IEqualityComparer? comparer) { @@ -472,6 +865,103 @@ public static IOrderedQueryable OrderByDescending(this I source.Expression, Expression.Quote(keySelector), Expression.Constant(comparer, typeof(IComparer)))); } + /// + /// Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing a right outer join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform an inner join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void LeftJoin() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.AsQueryable().RightJoin(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person?.Name, Pet = pet.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName ?? "NONE", + /// obj.Pet); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// NONE - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// */ + /// + /// + /// + /// + /// This method has at least one parameter of type whose type argument is one of the types. + /// For these parameters, you can pass in a lambda expression and it will be compiled to an . + /// + /// + /// The method + /// generates a that represents calling + /// + /// itself as a constructed generic method. + /// It then passes the to the method of the represented by the property of the parameter. + /// + /// + /// The query behavior that occurs as a result of executing an expression tree that represents calling + /// + /// depends on the implementation of the type of the parameter. + /// The expected behavior is that of a right outer join. + /// The and functions are used to extract keys from and , respectively. + /// These keys are compared for equality to match elements from each sequence. + /// A pair of elements is stored for each element in that matches an element in , plus a pair for each element in that has no matches in . + /// Then the function is invoked to project a result object from each pair of elements. + /// + /// [DynamicDependency("RightJoin`4", typeof(Enumerable))] public static IQueryable RightJoin(this IQueryable outer, IEnumerable inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector) { @@ -488,6 +978,104 @@ public static IQueryable RightJoin(this outer.Expression, GetSourceExpression(inner), Expression.Quote(outerKeySelector), Expression.Quote(innerKeySelector), Expression.Quote(resultSelector))); } + /// + /// Correlates the elements of two sequences based on matching keys. A specified is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// An to hash and compare keys. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing a right outer join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform an inner join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void LeftJoin() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.AsQueryable().RightJoin(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person?.Name, Pet = pet.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName ?? "NONE", + /// obj.Pet); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// NONE - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// */ + /// + /// + /// + /// + /// This method has at least one parameter of type whose type argument is one of the types. + /// For these parameters, you can pass in a lambda expression and it will be compiled to an . + /// + /// + /// The method + /// generates a that represents calling + /// + /// itself as a constructed generic method. + /// It then passes the to the method of the represented by the property of the parameter. + /// + /// + /// The query behavior that occurs as a result of executing an expression tree that represents calling + /// + /// depends on the implementation of the type of the parameter. + /// The expected behavior is that of a right outer join. + /// The and functions are used to extract keys from and , respectively. + /// These keys are compared for equality to match elements from each sequence. + /// A pair of elements is stored for each element in that matches an element in , plus a pair for each element in that has no matches in . + /// Then the function is invoked to project a result object from each pair of elements. + /// + /// [DynamicDependency("RightJoin`4", typeof(Enumerable))] public static IQueryable RightJoin(this IQueryable outer, IEnumerable inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector, IEqualityComparer? comparer) { diff --git a/src/libraries/System.Linq/src/System/Linq/Join.cs b/src/libraries/System.Linq/src/System/Linq/Join.cs index e9fc4a73afc09d..677f6bd0eb8b36 100644 --- a/src/libraries/System.Linq/src/System/Linq/Join.cs +++ b/src/libraries/System.Linq/src/System/Linq/Join.cs @@ -7,9 +7,210 @@ namespace System.Linq { public static partial class Enumerable { + /// + /// Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing an inner join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform an inner join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void JoinEx1() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { magnus, terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.Join(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person.Name, Pet = pet.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName, + /// obj.Pet); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// Hedlund, Magnus - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// */ + /// + /// + /// + /// + /// This method is implemented by using deferred execution. The immediate return value is an object that stores + /// all the information that is required to perform the action. The query represented by this method is not + /// executed until the object is enumerated either by calling its GetEnumerator method directly or by + /// using foreach in C# or For Each in Visual Basic. + /// + /// + /// The default equality comparer, , is used to hash and compare keys. + /// + /// + /// A join refers to the operation of correlating the elements of two sources of information based on a common key. + /// + /// brings the two information sources and the keys by which they are matched together in one method call. + /// + /// + /// In relational database terms, the method implements an inner equijoin. + /// 'Inner' means that only elements that have a match in the other sequence are included in the results. + /// An 'equijoin' is a join in which the keys are compared for equality. + /// An left outer join can be performed using the + /// method, + /// and a right outer join can be performed using the + /// method, + /// For more information, see Join operations. + /// + /// public static IEnumerable Join(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector) => Join(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer: null); + /// + /// Correlates the elements of two sequences based on matching keys. A specified is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// An to hash and compare keys. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing an inner join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform an inner join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void JoinEx1() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { magnus, terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.Join(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person.Name, Pet = pet.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName, + /// obj.Pet); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// Hedlund, Magnus - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// */ + /// + /// + /// + /// + /// This method is implemented by using deferred execution. The immediate return value is an object that stores + /// all the information that is required to perform the action. The query represented by this method is not + /// executed until the object is enumerated either by calling its GetEnumerator method directly or by + /// using foreach in C# or For Each in Visual Basic. + /// + /// + /// The default equality comparer, , is used to hash and compare keys. + /// + /// + /// A join refers to the operation of correlating the elements of two sources of information based on a common key. + /// + /// brings the two information sources and the keys by which they are matched together in one method call. + /// + /// + /// In relational database terms, the method implements an inner equijoin. + /// 'Inner' means that only elements that have a match in the other sequence are included in the results. + /// An 'equijoin' is a join in which the keys are compared for equality. + /// An left outer join can be performed using the + /// method, + /// and a right outer join can be performed using the + /// method, + /// For more information, see Join operations. + /// + /// public static IEnumerable Join(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector, IEqualityComparer? comparer) { if (outer is null) diff --git a/src/libraries/System.Linq/src/System/Linq/LeftJoin.cs b/src/libraries/System.Linq/src/System/Linq/LeftJoin.cs index 10130cc7eddc28..097e2453d0167e 100644 --- a/src/libraries/System.Linq/src/System/Linq/LeftJoin.cs +++ b/src/libraries/System.Linq/src/System/Linq/LeftJoin.cs @@ -7,9 +7,208 @@ namespace System.Linq { public static partial class Enumerable { + /// + /// Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing a left outer join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform aa left outer join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void LeftJoin() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { magnus, terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.LeftJoin(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person.Name, Pet = pet?.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName, + /// obj.Pet ?? "NONE"); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// Hedlund, Magnus - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// Chapkin, Tom - NONE + /// */ + /// + /// + /// + /// + /// This method is implemented by using deferred execution. The immediate return value is an object that stores + /// all the information that is required to perform the action. The query represented by this method is not + /// executed until the object is enumerated either by calling its GetEnumerator method directly or by + /// using foreach in C# or For Each in Visual Basic. + /// + /// + /// The default equality comparer, , is used to hash and compare keys. + /// + /// + /// A join refers to the operation of correlating the elements of two sources of information based on a common key. + /// + /// brings the two information sources and the keys by which they are matched together in one method call. + /// + /// + /// In relational database terms, the method implements an outer left equijoin. + /// 'Outer left' means that elements of the first sequence are returned regardless of whether matching elements are found in the other sequence. + /// An 'equijoin' is a join in which the keys are compared for equality. + /// An inner join - where only elements that have a match in the other sequence are included in the results - can be performed using the + /// method. + /// For more information, see Join operations. + /// + /// public static IEnumerable LeftJoin(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector) => LeftJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer: null); + /// + /// Correlates the elements of two sequences based on matching keys. A specified is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// An to hash and compare keys. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing a left outer join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform aa left outer join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void LeftJoin() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { magnus, terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.LeftJoin(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person.Name, Pet = pet?.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName, + /// obj.Pet ?? "NONE"); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// Hedlund, Magnus - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// Chapkin, Tom - NONE + /// */ + /// + /// + /// + /// + /// This method is implemented by using deferred execution. The immediate return value is an object that stores + /// all the information that is required to perform the action. The query represented by this method is not + /// executed until the object is enumerated either by calling its GetEnumerator method directly or by + /// using foreach in C# or For Each in Visual Basic. + /// + /// + /// The default equality comparer, , is used to hash and compare keys. + /// + /// + /// A join refers to the operation of correlating the elements of two sources of information based on a common key. + /// + /// brings the two information sources and the keys by which they are matched together in one method call. + /// + /// + /// In relational database terms, the method implements an outer left equijoin. + /// 'Outer left' means that elements of the first sequence are returned regardless of whether matching elements are found in the other sequence. + /// An 'equijoin' is a join in which the keys are compared for equality. + /// An inner join - where only elements that have a match in the other sequence are included in the results - can be performed using the + /// method. + /// For more information, see Join operations. + /// + /// public static IEnumerable LeftJoin(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector, IEqualityComparer? comparer) { if (outer is null) diff --git a/src/libraries/System.Linq/src/System/Linq/RightJoin.cs b/src/libraries/System.Linq/src/System/Linq/RightJoin.cs index b2524136c9c9cb..2485b7c13a281c 100644 --- a/src/libraries/System.Linq/src/System/Linq/RightJoin.cs +++ b/src/libraries/System.Linq/src/System/Linq/RightJoin.cs @@ -7,9 +7,206 @@ namespace System.Linq { public static partial class Enumerable { + /// + /// Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing a right outer join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform aa left outer join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void RightJoin() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.RightJoin(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person?.Name, Pet = pet.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName ?? "NONE", + /// obj.Pet); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// NONE - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// */ + /// + /// + /// + /// + /// This method is implemented by using deferred execution. The immediate return value is an object that stores + /// all the information that is required to perform the action. The query represented by this method is not + /// executed until the object is enumerated either by calling its GetEnumerator method directly or by + /// using foreach in C# or For Each in Visual Basic. + /// + /// + /// The default equality comparer, , is used to hash and compare keys. + /// + /// + /// A join refers to the operation of correlating the elements of two sources of information based on a common key. + /// + /// brings the two information sources and the keys by which they are matched together in one method call. + /// + /// + /// In relational database terms, the method implements an outer right equijoin. + /// 'Outer right' means that elements of the second sequence are returned regardless of whether matching elements are found in the other sequence. + /// An 'equijoin' is a join in which the keys are compared for equality. + /// An inner join - where only elements that have a match in the other sequence are included in the results - can be performed using the + /// method. + /// For more information, see Join operations. + /// + /// public static IEnumerable RightJoin(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector) => RightJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer: null); + /// + /// Correlates the elements of two sequences based on matching keys. A specified is used to compare keys. + /// + /// The first sequence to join. + /// The sequence to join to the first sequence. + /// A function to extract the join key from each element of the first sequence. + /// A function to extract the join key from each element of the second sequence. + /// A function to create a result element from two matching elements. + /// An to hash and compare keys. + /// The type of the elements of the first sequence. + /// The type of the elements of the second sequence. + /// The type of the keys returned by the key selector functions. + /// The type of the result elements. + /// An that has elements of type that are obtained by performing a right outer join on two sequences. + /// or or or or is . + /// + /// + /// The following code example demonstrates how to use to perform aa left outer join of two sequences based on a common key. + /// + /// + /// class Person + /// { + /// public string Name { get; set; } + /// } + /// + /// class Pet + /// { + /// public string Name { get; set; } + /// public Person Owner { get; set; } + /// } + /// + /// public static void RightJoin() + /// { + /// Person magnus = new Person { Name = "Hedlund, Magnus" }; + /// Person terry = new Person { Name = "Adams, Terry" }; + /// Person charlotte = new Person { Name = "Weiss, Charlotte" }; + /// Person tom = new Person { Name = "Chapkin, Tom" }; + /// + /// Pet barley = new Pet { Name = "Barley", Owner = terry }; + /// Pet boots = new Pet { Name = "Boots", Owner = terry }; + /// Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; + /// Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; + /// + /// List{Person} people = new List{Person} { terry, charlotte, tom }; + /// List{Pet} pets = new List{Pet} { barley, boots, whiskers, daisy }; + /// + /// // Create a list of Person-Pet pairs where + /// // each element is an anonymous type that contains a + /// // Pet's name and the name of the Person that owns the Pet. + /// var query = + /// people.RightJoin(pets, + /// person => person, + /// pet => pet.Owner, + /// (person, pet) => + /// new { OwnerName = person?.Name, Pet = pet.Name }); + /// + /// foreach (var obj in query) + /// { + /// Console.WriteLine( + /// "{0} - {1}", + /// obj.OwnerName ?? "NONE", + /// obj.Pet); + /// } + /// } + /// + /// /* + /// This code produces the following output: + /// + /// NONE - Daisy + /// Adams, Terry - Barley + /// Adams, Terry - Boots + /// Weiss, Charlotte - Whiskers + /// */ + /// + /// + /// + /// + /// This method is implemented by using deferred execution. The immediate return value is an object that stores + /// all the information that is required to perform the action. The query represented by this method is not + /// executed until the object is enumerated either by calling its GetEnumerator method directly or by + /// using foreach in C# or For Each in Visual Basic. + /// + /// + /// The default equality comparer, , is used to hash and compare keys. + /// + /// + /// A join refers to the operation of correlating the elements of two sources of information based on a common key. + /// + /// brings the two information sources and the keys by which they are matched together in one method call. + /// + /// + /// In relational database terms, the method implements an outer right equijoin. + /// 'Outer right' means that elements of the second sequence are returned regardless of whether matching elements are found in the other sequence. + /// An 'equijoin' is a join in which the keys are compared for equality. + /// An inner join - where only elements that have a match in the other sequence are included in the results - can be performed using the + /// method. + /// For more information, see Join operations. + /// + /// public static IEnumerable RightJoin(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector, IEqualityComparer? comparer) { if (outer is null)