2011-02-15 68 views
2

想知道是否有更好的方法来处理多个相似的条件语句和操作,如下面的示例代码片段所示。避免连续的类似条件块的方式

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

的,如果条件和除了字典操作在我看来,作为冗余,从而寻找出更高效,更优雅的方式实现代码。

谢谢!

更新:我使用.NET 3.5

+0

为了减少空间,您可以将语句放在与条件相同的行上,但我无法看到任何方式来摆脱长长的条件列表。抱歉。 – Darkhydro 2011-02-15 07:37:29

回答

4

您可以创建一个辅助类,它提供了一个试验中对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); 
    } 
-1

有两种方式: 1.使用开关的情况下 2.使用三元操作符

都将让你的代码看起来很干净,但在你的情况下开关的情况下无法正常工作。

+0

只有在只有一种情况适用的情况下,才能使用开关盒。我不认为这是这种情况。我也不知道三元运营商将如何帮助这里。 – codymanix 2011-02-15 08:14:08

2

一种选择是有某种条件列表和这些条件所代表的常量。例如:

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

注然后在任何地方重复使用它,因为列表本身不会改变。

+0

谢谢,但我正在使用.NET 3.5。 :( Tuple将会是什么合适的替代品? – Dienekes 2011-02-15 12:35:54

+0

@Dienekes:你可以很容易地编写自己的Tuple等价物,或者根据Fencliff的答案自定义类型 - 尽管我不会使用可变结构 – 2011-02-15 12:47:05

0

考虑在YourCustomClass中封装属性集合。这将保护你的属性免受意外改变,并且它将把属性填充到它所属的数据。

优点:

  • 您可以更改属性,随时填补实施,在不改变客户端(条件,谓词集合等)。
  • 更干净客户
  • 更容易维护

所以,即使您的默认实现使用将是这样的:

dc.SetStaus(string statusFlag) 

而且所有的肮脏的工作将内部直流完成(BTW我建议使用枚举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); 
} 

Afte r你可以轻松地重构实现:

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

梅。这不是真的多余的,除非你想考虑像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)