Способ (ы) избежать непрерывных, похожих условных блоков - PullRequest
2 голосов
/ 15 февраля 2011

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

private void AddCommonDictionaryItemsForAllAttributes(MyCustomType dc, string statusFlag)
{
    if (dc.xmlAttributes == null) {
        dc.xmlAttributes = new Dictionary<string, string>();
    }
    dc.xmlAttributes.Add(Constant.CD_1, statusFlag);
    dc.xmlAttributes.Add(Constant.CD_2, statusFlag);
    dc.xmlAttributes.Add(Constant.CD_3, statusFlag);
    if (dc.primaryZone != null) {
        dc.xmlAttributes.Add(Constant.CD_4, statusFlag);
    }
    if (dc.Mgr1 != null) {
        dc.xmlAttributes.Add(Constant.CD_10, statusFlag);
    }
    if (dc.Mgr2 != null) {
        dc.xmlAttributes.Add(Constant.CD_11, statusFlag);
    }
    if (dc.Mgr3 != null) {
        dc.xmlAttributes.Add(Constant.CD_5, statusFlag);
    }    
    if (dc.Producer != null) {
        dc.xmlAttributes.Add(Constant.CD_6, statusFlag);
    }
    if (dc.CountTest > 0) {
        dc.xmlAttributes.Add(Constant.CD_7, statusFlag);
    }
    if (dc.List1 != null && dc.List1.Count > 0) {
        dc.xmlAttributes.Add(Constant.CD_8, statusFlag);
    }
    if (dc.List2 != null && dc.List2.Count > 0) {
        dc.xmlAttributes.Add(Constant.CD_9, statusFlag);
    }
}

Кажется, что условия if и дополнение к операции словаряя как избыточный, поэтому ищу более эффективные и элегантные способы кодирования этого.

Спасибо!

Обновление: я использую .NET 3.5

Ответы [ 6 ]

4 голосов
/ 15 февраля 2011

Вы можете создать вспомогательный тип, который предоставляет тест для экземпляра MyCustomType и ключ для использования в словаре xmlAttributes:

class Rule
{
    private readonly Predicate<MyCustomType> _test;
    private readonly string _key;

    public Predicate<MyCustomType> Test { get { return _test; } }
    public string Key { get { return _key;  } }

    public Rule(Predicate<MyCustomType> test, string key)
    {
        _test = test;
        _key = key;
    }
}

Затем вы можете создать набор этих правил и перечислить их:

    private void AddCommonDictionaryItemsForAllAttributes(MyCustomType dc, string statusFlag)
    {

        var rules = new Rule[]
        {
            new Rule(x => x.Mgr1 != null, Constant.CD_4),
            new Rule(x => x.Mgr2 != null, Constant.CD_10),
            //...snip...
            new Rule(x => x.List2 != null && x.List2.Count > 0, Constant.CD_9)
        };

        foreach(var rule in rules.Where(r => r.Test(dc)))
            dc.xmlAttributes.Add(rule.Key, statusFlag);
    }
2 голосов
/ 15 февраля 2011

Один из вариантов - иметь некоторый список условий и констант, представленных этими условиями. Например:

var list = new List<Tuple<Predicate<MyCustomType>, string>>
{
    Tuple.Create(dc => true, Constant.CD_1),
    Tuple.Create(dc => true, Constant.CD_2),
    Tuple.Create(dc => true, Constant.CD_3),
    Tuple.Create(dc => dc.primaryZone != null, Constant.CD_4),
    Tuple.Create(dc => dc.Mgr1 != null, Constant.CD_5),
    // etc
};

Тогда вы могли бы просто перебирать список, устанавливая релевантное значение status в словаре всякий раз, когда предикат был истинным:

foreach (var tuple in list)
{
    if (tuple.Item1(dc))
    {
        dc.xmlAttributes.Add(tuple.Item2, statusFlag);
    }
}

Обратите внимание, что вы можете настроить список статически один раз, а затем использовать его везде, так как сам список не меняется.

1 голос
/ 15 февраля 2011

Вы можете сделать это в цикле for, потому что вы можете привести к перечислению .

0 голосов
/ 16 февраля 2011

Мех.Это на самом деле не избыточно, если только вы не хотите рассмотреть что-то вроде отражения Java.Рассмотрим вспомогательные методы:

void addIfOk(int test, MyCustomType dc, String attr, string statusFlag) {
  if(test!=0) dc.xmlAttributes.Add(attr, statusFlag);
}
void addIfOk(Object test, MyCustomType dc, String attr, string statusFlag) {
  if(test!=null) dc.xmlAttributes.Add(attr, statusFlag);
}
void addIfOk(Collection test, MyCustomType dc, String attr, string statusFlag) {
  if(test!=null&&!test.isEmpty()) dc.xmlAttributes.Add(attr, statusFlag);
}

Код становится:

    addIfOk(dc.Mgr1, dc, Constant.CD_10, statusFlag);
    addIfOk(dc.Mgr2, dc, Constant.CD_11, statusFlag);
    addIfOk(dc.Mgr3, dc, Constant.CD_5, statusFlag);
    addIfOk(dc.Producer, dc, Constant.CD_5, statusFlag);

и так далее.Возможно, это будет более целесообразно как метод внутри вашего пользовательского типа: setXmlStatusAttributes(statusfFlag)

0 голосов
/ 15 февраля 2011

Рассмотрим инкапсуляцию коллекции атрибутов внутри YourCustomClass. Это защитит ваши атрибуты от случайного изменения и переместит атрибуты, заполняющие логику, к данным, которым они принадлежат.

Преимущества:

  • Вы можете в любое время изменить реализацию заполнения атрибутов, не меняя клиентов (условия, сбор предикатов и т. Д.).
  • Гораздо более чистый клиент
  • Более простое обслуживание

Таким образом, даже при использовании по умолчанию реализация будет выглядеть следующим образом:

dc.SetStaus(string statusFlag)

И вся грязная работа будет выполняться внутри dc (кстати, я советую использовать enum CD вместо констант, но это зависит от вас):

public void SetStatus(string statusFlag)
{
    if (_xmlAttributes == null)
        _xmlAttributes = new Dictionary<CD, string>();

    _xmlAttributes.Add(CD.CD_1, statusFlag);
    _xmlAttributes.Add(CD.CD_2, statusFlag);
    _xmlAttributes.Add(CD.CD_3, statusFlag);

    if (_primaryZone != null)
        _xmlAttributes.Add(CD.CD_4, statusFlag);

    if (_mgr1 != null)
        _xmlAttributes.Add(CD.CD_10, statusFlag);

    if (_mgr2 != null)
        _xmlAttributes.Add(CD.CD_11, statusFlag);

    if (_mgr3 != null)
        _xmlAttributes.Add(CD.CD_5, statusFlag);

    if (_producer != null)
        _xmlAttributes.Add(CD.CD_6, statusFlag);

    if (_countTest > 0)
        _xmlAttributes.Add(CD.CD_7, statusFlag);

    if (_list1 != null && _list1.Count > 0)
        _xmlAttributes.Add(CD.CD_8, statusFlag);

    if (_list2 != null && _list2.Count > 0)
        _xmlAttributes.Add(CD.CD_9, statusFlag);
}

После этого вы можете легко изменить реализацию:

private Dictionary<CD, Func<bool>> _statusSetConditions;

public MyCustomType()
{
    _statusSetConditions = new Dictionary<CD, Func<bool>>();
    _statusSetConditions.Add(CD.CD_1, () => true);
    _statusSetConditions.Add(CD.CD_2, () => true);
    _statusSetConditions.Add(CD.CD_3, () => true);
    _statusSetConditions.Add(CD.CD_4, () => _primaryZone != null);
    ...
    _statusSetConditions.Add(CD.CD_11, () => _mgr2 != null);
}

public void SetStatus(string statusFlag)
{
    if (_xmlAttributes == null)
        _xmlAttributes = new Dictionary<CD, string>();

    foreach (CD cd in Enum.GetValues(typeof(CD)))
        AddStatusAttribute(cd, statusFlag);
}

private void AddStatusAttribute(CD cd, string statusFlag)
{
    Func<bool> condition;

    if (!_statusSetConditions.TryGetValue(cd, out condition))
        return; // or throw exception

    if (condition())
        _xmlAttributes.Add(cd, statusFlag);
}  

А клиент все еще просто вызывает dc.SetStatus (statusFlag);

Возможно, после инкапсуляции этой логики установки статуса, вы просто сохраните статус в поле YourCustomClass.

0 голосов
/ 15 февраля 2011

Существует два способа: 1. Использовать кейс переключателя 2. Использовать оператор Ternary

и то и другое сделает ваш код чистым, однако в вашем случае кейс переключателя не работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...