views:

113

answers:

5

Hi Guys. I need some help on simplifying my method

I have this method

public double ComputeBasicAmount(double basicLimit, double eligibleAmt)
{
  return basicLimit * eligibleAmt;
}

sample usage:

Foo foo = new Foo(100, 1000);
double basicAmt = ComputeBasicAmount(foo.BasicLimit, foo.EligibleAmt)

The problem here is I want the eligibleAmt to be dynamic because sometimes it's not really only the eligbleAmt what I'm passing to the method.. like this

Foo foo = new Foo(100, 1000);
double basicAmt = ComputeBasicAmount(foo.BasicLimit, foo.EligibleAmt/foo.RoomRate)

My solution is use the Func delegate as a parameter but i don't know how to use it properly

i want something functional like this

public double ComputeBasicAmount<T>(double basicLimit, Func<T, double> multiplier)
{

 return basicLimt * multiplier;
}

double basicAmt = ComputeBasicAmount<Foo>(foo.BasicLimit, x => x.EligibleAmt/x.RoomRate)

can someone help me. thanks in advance...

A: 

You'd declare your method something like this, so the multiplier is a delegate that takes a Foo object and returns a double:

double ComputeBasicAmount(
   double basicLimit, Foo foo, Func<Foo, double> multiplier)

Then call it like this, passing a lambda into the multiplier:

double basicAmt = ComputeBasicAmount(
   foo.BasicLimit, foo, x => x.EligibleAmt / x.RoomRate);
cxfx
This isn't correct as a `Foo` instance is not being passed in so there's nothing for the `ComputeBasicAmount` to call the `Func` with.
Enigmativity
Absolutely right, fixed.
cxfx
thanks but my method is the same as yours the difference is mine is Generic
CSharpNoob
A: 

You should use a Func<double> since you only use the double result

public double ComputeBasicAmount(double basicLimit, Func<double> multiplier)
{    
    return basicLimt * multiplier();
}

Then call it like this

double basicAmt = ComputeBasicAmount<Foo>(foo.BasicLimit, x => x.EligibleAmt/x.RoomRate)

But then you could have a regular double parameter instead.

Albin Sunnanbo
+3  A: 

You can declare it simply as a Func<double> (that way you are not making the method dependent on the Foo type), and pass any method taking no parameters and returning a double as argument:

public static double ComputeBasicAmount(double basicLimit, Func<double> multiplier)
{
    return basicLimit * multiplier();
}

Some example calls:

class Foo
{
    public double One;
    public double Two;
}


Foo f = new Foo();
double result = ComputeBasicAmount(f.One, () => f.Two);

You can also have some other method returning a double

public static double GetDoubleValue()
{
    return 4.2;
}

...and pass that as argument:

double result = ComputeBasicAmount(42,GetDoubleValue);
Fredrik Mörk
I was typing a similar answer...you beat me :) +1
Perpetualcoder
can you do a Generic version of this, because its not FOO object what im going to pass. thanks
CSharpNoob
oh man, I guess I don't have to use Generics here because I do not have to pass the Type... thanks man...
CSharpNoob
@user444024: exactly. The method is already as generic as it gets, given that we always want to operate on `double` values.
Fredrik Mörk
+1  A: 

If the multiplier depends on the item then either you'll need to pass the item as well, or you'll need to return a Func<T, double>:

public double ComputeBasicAmount<T>(double basicLimit,
                                    Func<T, double> multiplier,
                                    T item)
{    
    return basicLimt * multiplier(item);
}
...

double basicAmt = ComputeBasicAmount<Foo>(
                        foo.BasicLimit,
                        x => x.EligibleAmt / x.RoomRate,
                        foo)

or

public Func<T, double> ComputeBasicAmount<T>(double basicLimit,
                                             Func<T, double> multiplier)
{    
    return item => basicLimt * multiplier(item);
}
...
var basicAmtFunc = ComputeBasicAmount<Foo>(
                        foo.BasicLimit,
                        x => x.EligibleAmt / x.RoomRate);

var basicAmt = basicAmntFunc(foo);

If neither of those is what you were looking for, please explain where you want the actual value of T to be provided so that you can work out the multiplier.

The first is very similar to just having a Func<double> to compute the multiplier, of course... which in turn is pretty much like calling that Func<double> when computing the arguments, to get back to your original version which just takes two doubles.

Jon Skeet
I can use this if I need the actual value of T, but for this scenario I'm only evaluating double value property of different objects . Thanks...
CSharpNoob
A: 

Thanks guys, With your help I was able to make my existing code much more readable and functional...

    class RNB
    {
        public RNB(double roomRate, double roomDays)
        {
            RoomRate = roomRate;
            RoomDays = roomDays;
        }

        public double RoomRate { get; set; }
        public double RoomDays { get; set; }
        public const double BasicLimit = 100;
    }

    class HMS
    {
        public double Amount { get; set; }
        public const double BasicLimit = 200;
    }

    public static double ComputeBasicAmount(double basicLimit, Func<double> multiplier)
    {
        return basicLimit * multiplier();
    }

    static void Main(string[] args)
    {
        RNB rnb = new RNB(100, 2);
        double result = ComputeBasicAmount(RNB.BasicLimit, () => rnb.RoomDays * rnb.RoomRate);
        Console.WriteLine("RNB Basic Amt: " + result.ToString());

        HMS hms = new HMS() { Amount = 1000 };
        result = ComputeBasicAmount(HMS.BasicLimit, () => hms.Amount);
        Console.WriteLine("HMS Basic Amt: " + result.ToString());

        Console.Read();
    }

But I have another problem here.. I Want to eliminate the passing of the BasicLimit because i think it looks redundant here. Is it possible to put the BasicLimit inside the ComputeBasicAmount method

Something like this..

 public static double ComputeBasicAmount<T>(Func<T, double> multiplier, T obj)
  {

      return obj.BasicLimit * multiplier();
  }

But I have to put this question in another thread because I think its another topic... See you guys there... thanks...

CSharpNoob