开发者

Coding Enhancement: Generic Method using Func<T> as parameter

I have this two objects

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

        public double RoomRate { get; set; }
        publi开发者_C百科c double RoomDays { get; set; }
        public const double BasicLimit = 100;
    }

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

And then I have this method:

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

Sample usage:

    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();
    }

The 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();
  }

Thanks in advance guys...

PS: The basicLimit doesn't have to be CONST


Yes you could, but you would have to check the type of obj first, since you can't restrict the type parameter to be of a specific class.

This means you can't define ComputeBasicAmount to only be called as ComputeBasicAmount<RNB> and ComputeBasicAmount<HMS>.

But, you could check if obj is either of the type RNB or HMS:

public static double ComputeBasicAmount<T>(Func<T, double> multiplier, T obj)
{
    var cObj1 = obj as RNB;
    if(cObj1!=null)
        return cObj1.BasicLimit * multiplier();

    var cObj2 = obj as HMS;
    if(cObj2 != null)
        return cObj1.BasicLimit * multiplier(); 

    return null; //Or throw an exception, e.g. argument exception
}


Well, all that this method does is multiple two double operands. There's already an operator for this. Can't you simply do this:

RNB rnb = new RNB(100, 2);
double result = RNB.BasicLimit * rnb.RoomDays * rnb.RoomRate;

HMS hms = new HMS() { Amount = 1000 };
result = HMS.BasicLimit * hms.Amount;


No, you can't do it like that... even if you put in an interface, you can't specify that an instance method must be static, and then call it via T. You would have to use reflection, basically... and I think that's far uglier than specifying the room limit explicitly. You may want to read my proposal around static interfaces for a little more on this.

Essentially your two BasicLimit constants are unrelated as far as the compiler is concerned.

As you're already creating instances of the rooms, you could have an interface:

public interface IRoomType
{
    double BasicLimit { get; }
}

and then pass the instance of the room into the method, and ask it to fetch the limit that way. That's ugly because it's using an instance member to get at a value which isn't really specific to any particular instance, but that's the way of it.

If you are going to use reflection, you might want to consider specifying the limit in an attribute instead of a constant:

[BasicLimit(100)]
public class RNB { ... }

Then you could at least ask the type of T for the BasicLimitAttribute applied to it, if any. You wouldn't have compile-time safety that the attribute existed, but you would have safety against typos such as making one constant BascLimit instead of BasicLimit.


Perhaps a simpler answer here is to produce extension methods for the classes and just call ComputeBasicAmount without any parameters?

public static class ComputeBasicAmountEx
{
    public static double ComputeBasicAmount(this RNB rnb)
    {
        return RNB.BasicLimit * rnb.RoomDays * rnb.RoomRate;
    }

    public static double ComputeBasicAmount(this HMS hms)
    {
        return HMS.BasicLimit * hms.Amount;
    }
}

Your code then looks like this:

RNB rnb = new RNB(100, 2);
double result = rnb.ComputeBasicAmount();
Console.WriteLine("RNB Basic Amt: " + result.ToString());

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

However, I don't think this is the best answer. I think I would prefer to create an interface and have the classes implement the interface, but the final code will still look the same.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜