views:

336

answers:

12

How can I do this elegantly with C# and .Net 3.5/4?

For example a number can be between 1 and 100.

Edit: I know a simple if would suffice; but the keyword to this question is elegance. It's for my toy project not for production.

Edit 2: This questions wasn't about speed but about code beauty. Stop talking about efficiency and such; remember you're preaching to the choir.

+16  A: 

You mean?

if(number > 1 && number < 100)

or

bool TestRange (int numberToCheck, int bottom, int top)
{
  return (numberToCheck > bottom && numberToCheck < top);
}
Kevin
That's all you need, and is elegant enough...
Matthew Abbott
You don't need "is" in there... This won't compile. (Otherwise, I agree 100%)
Reed Copsey
You stole my algorithm :-)
Ben Hoffstein
Thanks Reed. I feel so stupid for not seeing that.
Kevin
@Ben, just wait until I try and patent it too :)
Kevin
A: 

A new twist on an old favorite:

public bool IsWithinRange(int number, int topOfRange, int bottomOfRange, bool includeBoundaries) {
    if (includeBoundaries)
        return number <= topOfRange && number >= bottomOfRange;
    return number < topOfRange && number > bottomOfRange;
}
Ben Hoffstein
A: 
if (value > 1 && value < 100)
{
    // do work
}
else
{
    // handle outside of range logic
}
NickLarsen
+2  A: 

This is a real simple one. Doesnt have to be more elagant than an if statement. dont try to get too fancy. Never sacrifice simplicity for elegance.

Ben313
+3  A: 

Just to add to the noise here, you could create an extension method:

public static bool IsWithin(this int value, int minimum, int maximum)
{
    return value >= minimum && value <= maximum;
}

Which would let you do something like...

int val = 15;

bool foo = val.IsWithin(5,20);

That being said, this seems like a silly thing to do when the check itself is only one line.

Adam Robinson
@Ben: I went on the subject, which says "within a range" (which I don't think is ambiguous in that regard), but you're right in that the question body says "between 1 and 100" (which is, of course, ambiguous).
Adam Robinson
+1  A: 

There are a lot of options:

int x = 30;
if (Enumerable.Range(1,100).Contains(x))
    //true

if (x >= 1 && x <= 100)
    //true

Also, check out this SO post for regex options.

Dustin Laine
Enumerable.Range has to generate the enumerable of integers first, and then loop over each item to find it. That's a terrible idea and performance compared to checking a value is drastically different.I think we should adopt a moto, just because LINQ Extensions are cool, doesn't mean they should be used for everything.
Matthew Abbott
@Matthew: http://stackoverflow.com/questions/777400/what-is-the-biggest-mistake-people-make-when-starting-to-use-linq/777412#777412
Adam Robinson
I agree this is a terrible idea performance-wise, but the OP wants something more fancy than an `if` statement. This certainly accomplishes that... ;)
Tim Coker
@Matthew: Elegant not efficient!
Dustin Laine
The point of this question wasn't to debate what way is faster during execution. It was what code looks nicer and still gets the job done (again: I don't care about performance); this one wins by far. Easy to read and simple to use.
Sergio Tapia
+2  A: 

If this is incidental, a simple if is all you need. If this happens in many places, you might want to consider these two:

  • PostSharp. Decorate methods with attributes that 'inject' code into the method after compilation. I don't know for sure, but I can imagine it can be used for this.

Something like:

[Between("parameter", 0, 100)]
public void Foo(int parameter)
{
}
  • Code contracts. Has the advantage that the constraints can be checked at compile time, by static verification of your code and the places that use your code.
JulianR
+1 for code contracts; it's specific to validating a parameter, but it's a frequent use case and static verification has the potential to be extremely useful.
Dan Bryant
+3  A: 
(1 < value) ? (value < 100) : false;

By "Elegant", do you mean "intentionally difficult to read"?

Edit: Here's a more elegant solution.

new Rectangle(min, 1, max, 1).IntersectsWith(new Rectangle(value, 1, 1, 1));
Mark H
Is the edit being serious or not?
CaptainCasey
@Casey: VRY SRS BSNS
Mark H
+5  A: 

As others said, use a simple if.

You should think about the ordering.

e.g

1 <= x && x <= 100

is easier to read than

x => 1 && x <= 100
Esben Skov Pedersen
"Easier" is in the eye of the beholder. I personally prefer to have the variable in question on the left and the constant or variable *not* in question on the right.
Adam Robinson
In [Perl 6](http://dev.perl.org/perl6/rfc/25.html), you would write `1 <= x <= 100`.
Jordão
@Adam: Steve McConnell agrees with EsbenP that "number line" order is clearest (in Code Complete). Personally I agree with you. I suspect that's because I've been using that form for many years now.
MarkJ
I up-voted Kevin's answer, but then I saw this. Great answer.
CaptainCasey
A: 

In C, if time efficiency is crucial and integer overflows will wrap, one could do "if ((unsigned)(value-min) <= (max-min)) ...". If 'max' and 'min' are independent variables, the extra subtraction for (max-min) will waste time, but if that expression can be precomputed at compile time, or if it can be computed once at run-time to test many numbers against the same range, the above expression may be computed efficiently even in the case where the value is within range (if a large fraction of values will be below the valid range, it may be faster to use "if ((value >= min) && (value <= max)) ..." because it will "exit early" if value is less than min).

Before using an implementation like that, though, benchmark one one's target machine. On some processors, the two-part expression may be faster in all cases since the two comparisons may be done independently whereas in the subtract-and-compare method the subtraction has to complete before the compare can execute.

supercat
+2  A: 

With a bit of extension method abuse, we can get the following "elegant" solution:

using System;

namespace Elegant {
    public class Range {
        public int Lower { get; set; }
        public int Upper { get; set; }
    }

    public static class Ext {
        public static Range To(this int lower, int upper) {
            return new Range { Lower = lower, Upper = upper };
        }

        public static bool In(this int n, Range r) {
            return n >= r.Lower && n <= r.Upper;
        }
    }

    class Program {
        static void Main() {
            int x = 55;
            if (x.In(1.To(100)))
                Console.WriteLine("it's in range! elegantly!");
        }
    }
}
Ferruccio
+1  A: 

Using an && expression to join two comparisons is simply the most elegant way to do this. If you try using fancy extension methods and such, you run into the question of whether to include the upper bound, the lower bound, or both. Once you start adding additional variables or changing the extension names to indicate what is included, your code becomes longer and harder to read (for the vast majority of programmers). Furthermore, tools like Resharper will warn you if your comparison doesn't make sense (number > 100 && number < 1), which they won't do if you use a method ('i.IsBetween(100, 1)').

The only other comment I'd make is that if you're checking inputs with the intention to throw an exception, you should consider using code contracts:

Contract.Requires(number > 1 && number < 100)

This is more elegant than if(...) throw new Exception(...), and you could even get compile-time warnings if someone tries to call your method without ensuring that the number is in bounds first.

StriplingWarrior
FYI, the contracts static analyzer is happier when the lower bound and upper bound constraints are split into separate Requires statements.
Dan Bryant