Улучшение кодирования: общий метод с использованием Func <T>в качестве параметра - PullRequest
0 голосов
/ 10 сентября 2010

У меня есть два объекта

    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 голосов
/ 10 сентября 2010

Возможно, более простой ответ здесь - создать методы расширения для классов и просто вызвать 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());

Однако я не думаю, что это лучший ответ. Я думаю, что я бы предпочел создать интерфейс и сделать так, чтобы классы реализовали интерфейс, но окончательный код будет выглядеть так же.

0 голосов
/ 10 сентября 2010

Ну, все, что делает этот метод - это несколько двойных операндов.Там уже оператор для этого.Вы не можете просто сделать это:

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;
0 голосов
/ 10 сентября 2010

Нет, вы не можете делать это так ... даже если вы вставляете интерфейс, вы не можете указать, что метод экземпляра должен быть статическим, а затем вызывать его через T.Вам бы пришлось использовать отражение, в основном ... и я думаю, что это намного страшнее, чем явное указание предела комнаты.Вы можете прочитать мое предложение о статических интерфейсах , чтобы узнать больше об этом.

По сути, ваши две BasicLimit константы не имеют отношения к компилятору.

Поскольку вы уже создаете экземпляры комнат, вы можете иметь интерфейс:

public interface IRoomType
{
    double BasicLimit { get; }
}

, а затем передать экземпляр комнаты в метод и попросить его:получить предел таким образом.Это уродливо, потому что он использует элемент экземпляра, чтобы получить значение, которое на самом деле не является специфическим для какого-либо конкретного экземпляра, но это так.

Если вы собираетесь использовать отражение, вы можете захотеть указать ограничение в атрибуте вместо константы:

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

Тогда вы можете хотя бы спросить тип T для BasicLimitAttribute, примененного к нему, если таковой имеется.У вас не было бы безопасности во время компиляции, что атрибут существовал , но вы имели бы защиту от опечаток, таких как создание одной константы BascLimit вместо BasicLimit.

0 голосов
/ 10 сентября 2010

Да, вы можете, но сначала вам нужно будет проверить тип obj, поскольку вы не можете ограничить параметр типа определенным классом.

Это означает, что вы не можете определитьComputeBasicAmount должен вызываться только как ComputeBasicAmount<RNB> и ComputeBasicAmount<HMS>.

Но вы можете проверить, относится ли obj к типу RNB или 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
}
...