1

I wonder if it is possible to store an operator in some kind of variable. My code should be self explanatory.

But I wonder if it is possible to store:
<, >, >=
in some kind of variable and use it in an if statement like I try to do in the code or if there is another approach to achieve it?

String compare = "largerValue"; //largerEqualValue, equalValue
var useoperator = "";

if (compare == "largerValue") { useoperator = ">"; }
if (compare == "largerEqualValue") { useoperator = ">="; }
if (compare == "equalValue") { useoperator = "=="; }

for (int i = 0; i < 100000; i++)
{
    if( 20 useoperator 50) { } //Is it possible to assign an "useoperator" like this in any way?
}
Andreas
  • 1,121
  • 4
  • 17
  • 34
  • 2
    Does [this](https://stackoverflow.com/questions/14255618/store-an-operator-in-a-variable) answer your question? – Sweeper Apr 03 '20 at 12:41
  • @Sweeper, I was actually finding that post also before I posted the question. I am not sure if that does exactly what I try to do. I dont think so. It seems to use only + and - when I try to use >, >=, == etc – Andreas Apr 03 '20 at 12:44
  • I think you have the same question of this guy. Here is the link [C# dynamic operator [duplicate]](https://stackoverflow.com/questions/1207962/c-sharp-dynamic-operator) – KhailXpro Apr 03 '20 at 12:44
  • The question @Sweeper linked to would need adapting but is essentially what you should do. Hint: use `Func compare = (a, b) => a > b` instead – phuzi Apr 03 '20 at 12:58
  • @phuzi, yes you are right! I just noticed that this approach takes more than double the time than using a normal operator. I am not sure if is is possible to do as fast as a normal operator? – Andreas Apr 03 '20 at 12:59

4 Answers4

4

One way could be to store the operators as delegates in a dictionary:

var operators = new Dictionary<string, Func<int, int, bool>>();

operators.Add("largerValue", (a, b) => a > b);
operators.Add("largerEqualValue", (a, b) => a >= b);
operators.Add("equalValue", (a, b) => a == b);

Then you can just retrieve and call the operator when you need it:

var operator = operators[compare];

for (int i = 0; i < 100000; i++)
{
    if (operator(20, 50)) { } 
}
Kevin Gosse
  • 38,392
  • 3
  • 78
  • 94
  • Kevin, thank you. Yes that did actually work. As a sidenote, I tried the loop using this approach and noticed that `if (operator(20, 50)) { } ` takes more than double the time as for example `if( 20 > 50) {}` but I don't know if it is possible to make it as fast as a normal operator? – Andreas Apr 03 '20 at 12:53
  • 1
    @Andreas It'll always be slower, but more than double sounds a lot. Make sure you get the value from the dictionary outside of the loop – Kevin Gosse Apr 03 '20 at 12:59
  • yes I thought so too. I am getting the value outside the loop and with a normal operator it takes 4 seconds and with the approach it takes 10 seconds. So it is quite slow though. I trying to optimize some code so I am not sure I can use the approach after all even that it work in this case. – Andreas Apr 03 '20 at 13:01
0

Yeap, this is possible, your operator is simple boolean binary operator:

        Func<int, int, bool> useoperator = null;
        String compare = "largerValue"; //largerEqualValue, equalValue

        if (compare == "largerValue") { useoperator = (x,y)=> x > y; }
        if (compare == "largerEqualValue") { useoperator = (x,y)=> x >= y; }
        if (compare == "equalValue") { useoperator = (x,y)=> x == y; }

        for (int i = 0; i < 100000; i++)
        {
            if(useoperator(20, 50)) { }
        }
eocron
  • 6,885
  • 1
  • 21
  • 50
0

You can create a Func which has a delegate that evaluates your result.

Checkout the below code:

Func<int, int, bool> compareFunc = null;
if (compare == "largerValue")
{
    compareFunc = (a, b) => a > b;
}

if (compare == "largerEqualValue")
{
    compareFunc = (a, b) => a >= b;
}

if (compare == "equalValue")
{
    compareFunc = (a, b) => a == b;
}

for (var i = 0; i < 100000; i++)
{
    if (compareFunc != null && compareFunc(20, 50))
    {

    }
}

Kevin Smith
  • 13,746
  • 4
  • 52
  • 77
0

But what about performance?

Running the code below (LinqPad) resulted in

1,000,000,000 Native operations: 358,930,064 ticks
1,000,000,000 Dynamic operations: 369,853,643 ticks

Since there are 10,000 ticks in a millisecond this works out at:

1,000,000,000 Native operations: 35,893 ms
1,000,000,000 Dynamic operations: 36,985 ms

var stopwatch = new Stopwatch();
var iterations = 1_000_000_000;

var rng = new Random();
var greaterThan = 0;

stopwatch.Start();
for (var iteration = 0; iteration < iterations; iteration++){
    var (a, b) = (rng.Next(), rng.Next());

    if (a > b) {
        greaterThan++;
    }
}
stopwatch.Stop();

Console.WriteLine($"{iterations:0,000} Native operations: {stopwatch.ElapsedTicks:0,000} ticks");

Expression<Func<int, int, bool>> GreaterThan = (a, b) => a > b;
var compiled = GreaterThan.Compile();

greaterThan = 0;

stopwatch.Reset();
stopwatch.Start();
for (var iteration = 0; iteration < iterations; iteration++)
{
    var (a, b) = (rng.Next(), rng.Next());

    if (compiled(a,b))
    {
        greaterThan++;
    }
}
stopwatch.Stop();

Console.WriteLine($"{iterations:0,000} Dynamic operations: {stopwatch.ElapsedTicks:0,000} ticks");

Doing the same but using a lambda (Func<int, int, bool>) yielded very similar results:

1,000,000,000 Native operations: 354,127,563 ticks
1,000,000,000 Dynamic operations: 401,450,782 ticks

Or:

1,000,000,000 Native operations: 35,412 ms
1,000,000,000 Dynamic operations: 40,145 ms

Making it faster

The easy way to make the above code faster would be to remove the random number generation from within the loop. Just using 2 random numbers generated before either of the timed sections greatly reduces the the run time, to about 3.1 seconds (Native) and 7.9 seconds (Dynamic).

Conclusion

So, while it does seem to take about twice as long to use a dynamic operation instead of the native operation, the overall performance impact will likely be swamped by the rest of the code within the loop. In short, don't worry about it until it does actually become an issue.

Final thoughts

It is likely that there is a way to improve the performance of the dynamic check but doing so will likely reduce the maintainability of the code.

Disclaimer: The times seen here are very subjective and will depend upon the spec of the computer running the code

phuzi
  • 12,078
  • 3
  • 26
  • 50