编码增强:使用Func <t>作为参数的通用方法</t>

时间:2010-09-10 06:19:37

标签: c# delegates functional-programming

我有这两个对象

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

这里的问题,我想消除BasicLimit 的传递,因为我认为这看起来多余。是否可以将BasicLimit放在ComputeBasicAmount方法

像这样......

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

      return obj.BasicLimit * multiplier();
  }

先谢谢你们......

PS:basicLimit不一定是CONST

4 个答案:

答案 0 :(得分:0)

是的,你可以,但你必须首先检查obj的类型,因为你不能将类型参数限制为特定的类。

这意味着您无法将ComputeBasicAmount定义为仅ComputeBasicAmount<RNB>ComputeBasicAmount<HMS>

但是,您可以检查objRNB还是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
}

答案 1 :(得分:0)

嗯,这个方法所做的就是多个两个双操作数。已经有了这方面的运营商。你不能简单地这样做:

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;

答案 2 :(得分:0)

不,你不能这样做......即使你放入一个接口,你也不能指定一个实例方法必须是静态的,然后通过T调用它。你必须使用反射,基本上...而且我认为比明确指定房间限制更丑。您可能需要阅读我的proposal around static interfaces以获取更多信息。

就编译器而言,本质上你的两个BasicLimit常量是不相关的。

由于您已经创建了房间的实例,可以拥有一个界面:

public interface IRoomType
{
    double BasicLimit { get; }
}

然后将房间的实例传递给方法,并要求它以这种方式获取限制。这很难看,因为它使用实例成员来获取一个并非真正特定于任何特定实例的值,但这就是它的方式。

如果 要使用反射,您可能需要考虑在属性中指定限制而不是常量:

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

然后,您至少可以询问适用于T的{​​{1}}类型,如果有的话。您不具备属性存在的编译时安全性,但具有针对拼写错误的安全性,例如使一个常量BasicLimitAttribute而不是{{1 }}

答案 3 :(得分:0)

这里可能更简单的答案是为类生成扩展方法,只需在没有任何参数的情况下调用ComputeBasicAmount

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

您的代码如下所示:

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

但是,我不认为这是最好的答案。我想我更喜欢创建一个接口并让类实现接口,但最终的代码看起来仍然一样。