Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for specify return value on System.Linq.Enumerable.*OrDefault methods #48886

Merged
merged 14 commits into from
Mar 18, 2021

Conversation

Foxtrek64
Copy link
Contributor

Fixes #20064

@ghost
Copy link

ghost commented Feb 28, 2021

Tagging subscribers to this area: @eiriktsarpalis
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #20064

Author: Foxtrek64
Assignees: -
Labels:

area-System.Linq

Milestone: -

@Foxtrek64
Copy link
Contributor Author

Foxtrek64 commented Feb 28, 2021

Are the errors here code issues or an issue with changes being synced? I haven't contributed since the dotnet runtime was split across several repositories so I'm not familiar with all that's going on behind the scenes.

Edit: Didn't push ref assemblies. This has been resolved.

Base automatically changed from master to main March 1, 2021 09:08
Copy link
Member

@eiriktsarpalis eiriktsarpalis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add unit tests for the new methods as well. Thanks.

@eiriktsarpalis
Copy link
Member

Hi @Foxtrek64, have you been able to take a look at PR feedback? Thanks!

@Foxtrek64
Copy link
Contributor Author

Hi @Foxtrek64, have you been able to take a look at PR feedback? Thanks!

Yes. Sorry, I've had a busy few days. I'll implement these changes tomorrow and have them ready for review.

eiriktsarpalis
eiriktsarpalis previously approved these changes Mar 11, 2021
Copy link
Member

@eiriktsarpalis eiriktsarpalis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add similar unit tests for the overloads accepting predicates.

@eiriktsarpalis eiriktsarpalis dismissed their stale review March 11, 2021 16:13

approved accidentally, PR still has pending feedback

Copy link
Member

@eiriktsarpalis eiriktsarpalis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than some minor changes, LGTM.

Thank you for your contribution!

@eiriktsarpalis
Copy link
Member

Thanks @Foxtrek64. Note that there are a few failing unit tests related to these changes. Could you take a look?

@Foxtrek64
Copy link
Contributor Author

Foxtrek64 commented Mar 15, 2021

I did notice what I think was a logic error on my part and patched it. Hopefully it resolves the test issues, or at least some of them. I tried testing on my ends but I get strange results, like MissingMethodExceptions even after a build (which does fix some problems). I presume the entire environment has to be built, not just the individual projects.

Edit: I've fixed this issue but now I'm running into issues with the Queryable side of things. After hashing this out in the .Net Foundation Discord, we believe this to be an issue with the BCL itself in that the overload I'm attempting to implement does not exist there. I'm not entirely sure doing something like this is even possible given that it would require splitting things into multiple queries on the BCL side.

I can "fix" it by doing something like this:

[DynamicDependency("FirstOrDefault`1", typeof(Enumerable))]
public static TSource FirstOrDefault<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, TSource defaultValue)
{
    if (source == null)
        throw Error.ArgumentNull(nameof(source));
    if (predicate == null)
        throw Error.ArgumentNull(nameof(predicate));

    using var result = source.Where(predicate).Take(1).GetEnumerator();

    if (result.MoveNext())
        return result.Current;

    return defaultValue;

    // Skip this stuff
    /*   
    return source.Provider.Execute<TSource>(
        Expression.Call(
            null,
            CachedReflectionInfo.FirstOrDefault_TSource_4(typeof(TSource)),
            source.Expression, Expression.Quote(predicate), Expression.Constant(defaultValue, typeof(TSource))
        ));
    */
}

But this is less than ideal for the obvious reason that it cannot be used in the inner part of a query, like this:

var query = context.SomeTable.Select(t => t.SubTable.Select(st => st.Value).FirstOrDefault(v => v > 0, -1));

@eiriktsarpalis @stephentoub How would you recommend going about this? It may be best to only update System.Linq for IEnumerable for now and make a separate issue for Queryable since it potentially involves updating more than just the Linq libraries to implement. Or I can implement a simplification like in the above sample and we just document that it can't be used in an inner query but rather only to return the final value.

Alternatively, if you two or anyone else has any ideas, I'm all ears. It may be possible to implement this in an appropriate manner, but I'm not entirely certain what that might look like.

@eiriktsarpalis
Copy link
Member

@Foxtrek64 I rebased your branch and added fixes for the failing tests.

@Foxtrek64
Copy link
Contributor Author

@Foxtrek64 I rebased your branch and added fixes for the failing tests.

Seems a mix of me just being blind and missing a couple things and some random number being wrong somewhere that I would have never thought to look at. Glad we got that sorted.

@eiriktsarpalis eiriktsarpalis merged commit 122c438 into dotnet:main Mar 18, 2021
@eiriktsarpalis
Copy link
Member

Thanks @Foxtrek64!

@ghost ghost locked as resolved and limited conversation to collaborators Apr 17, 2021
@karelz karelz added this to the 6.0.0 milestone May 20, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow for specify return value on System.Linq.Enumerable.*OrDefault methods
4 participants