throw icon indicating copy to clipboard operation
throw copied to clipboard

Add collection .IfAny() .IfSingle() .IfNotSingle() .IfNone() .IfAll()

Open amantinband opened this issue 4 years ago • 14 comments

Add the following collection validations:

var collection = new[] { 1, 2, 3, 3 };

collection.Throw().IfAny(item => item == 3);
collection.Throw().IfSingle(item => item == 2);
collection.Throw().IfNotSingle(item => item == 3);
collection.Throw().IfNone(item => item == 0);
collection.Throw().IfAll(item => item > 0);

amantinband avatar Mar 10 '22 20:03 amantinband

@mantinband Just to clarify if single is when only one element in the collection is equal to 2 And not single is when more than one element is equal to 3

dwakel avatar Mar 11 '22 05:03 dwakel

I picked up this issue. Currently writing test. This is probably my first open-source contribution ever I've enjoyed working on this

dwakel avatar Mar 11 '22 07:03 dwakel

Awesome, that was quick! Let me know If you have any questions. Also, feel free to split this into multiple PRs if that would be more convenient 🙂

amantinband avatar Mar 11 '22 07:03 amantinband

@mantinband should these extensions be able to evaluate any type.

Im assuming for collection.Throw().IfAny(item => item == 3); It should accept an expression which can evaluate item => item > 3 item => item < 3 item => item <= 3 (Any inequality expression)

This however wont yield same results for a collection of strings unless a numeric property or function of the string (Count, Length, etc.) is Invoked

dwakel avatar Mar 11 '22 11:03 dwakel

I was thinking of something similar to this draft PR: https://github.com/mantinband/throw/pull/25 WDYT?

There is a C# language limitation that we cannot specify the method declaration as following:

    public static ref readonly Validatable<TValue> IfAny<TValue, TItem>(this in Validatable<TValue<TItem>> validatable, Func<TItem, bool> predicate, [CallerArgumentExpression("predicate")] string? predicateName = null)

Unfortunately in this implementation, we need to disambiguate the predicate's input parameter (int x in the draft PR). Couldn't find a way around this..

amantinband avatar Mar 11 '22 12:03 amantinband

@dwakel Take a look at the latest iteration of #25. This works as you would expect. The only downfall is that it boxes the Validatable struct which will hurt performance. I wonder if there is a way around this

amantinband avatar Mar 12 '22 13:03 amantinband

@mantinband I noticed the validatable doesn't return TCollectionType but just encapsulates an IEnumerable directly. It also didn't occur to me that you could just pass the inequality condition as a Func<item,bool> 😄 The picture I had in my mind was to accept an Expression type then evaluate it using LINQ

dwakel avatar Mar 13 '22 08:03 dwakel

Should these operations be limited to a subset ⊆ of Rational numbers

dwakel avatar Mar 20 '22 02:03 dwakel

Nah, I think the main use case will be on complex objects and not on collections of rational numbers/strings

amantinband avatar Mar 20 '22 11:03 amantinband

I'm going to jump back to working on this issue

dwakel avatar Mar 23 '22 05:03 dwakel

Hi there! Just jumping into the pool. Is the issue still being worked on? Or is it up for grabs? I'm eager to contribute to this lib, so if there's anything I can add... Might as well start here ^^

SakuraIsayeki avatar Sep 06 '22 11:09 SakuraIsayeki

Hey @SakuraIsayeki you could definitely look at this issue. Please also share any insights you have. It'll be nice knowing how you would go about implementing this

dwakel avatar Sep 06 '22 11:09 dwakel

Okay. I see where the snag lies.

To recap, the current issue has us unable to determine IfAny()'s TElement on this example :

Action action = () => collection.Throw().IfAny(x => x == "ho");
Action action2 = () => collection2.Throw().IfAny(x => x == 1);

Where IfAny() is plagued with the same issue, namely The type arguments for method 'ref readonly Validatable<TValue> Throw.ValidatableExtensions.IfAny<TValue,TElement>(this in Validatable<TValue>, Expression<Func<TElement,bool>>)' cannot be inferred from the usage..

Here's what I have so far: https://github.com/SakuraIsayeki/throw/commit/7e87a42620a54d8d6cfdb04f9fde972f33e5a0f1

This got me thinking...

How did they manage it on FluentAssertions?

FluentAssertions would have it as so:

collection.Should().Satisfy(x => x == "ho");
collection2.Should().Satisfy(x => x == 1);

And it just works. Here's the catch tho ; These buggers used IEnumerable<T> as the arg type on Should()! And honestly this is briliant. They're essentially only exposing one generic, and that's the Item type.


I suspect what's left to do is to somehow hack Throw() around accepting IEnumerable<T> as its entry parameter. Could you please @amantinband advise us on how feasible this would be, in regards to the library itself, and how you've planned its development this far?

SakuraIsayeki avatar Sep 06 '22 18:09 SakuraIsayeki

Any update on this? It would be really useful to have this feature.

Mitchman215 avatar Aug 09 '23 21:08 Mitchman215