2011-10-04 92 views
2

注视虽然该项目的一些代码,我的工作,我已经遇到这确实 以下一个相当丰厚的方法:如何摆脱重复的if语句?

public string DataField(int id, string fieldName) 
{ 
    var data = _dataRepository.Find(id); 
    if (data != null) 
    { 
     if (data.A == null) 
     { 
     data.A = fieldName; 
     _dataRepository.InsertOrUpdate(data); 
     return "A"; 
     } 

     if (data.B == null) 
     { 
     data.B = fieldName; 
     _dataRepository.InsertOrUpdate(data); 
     return "B"; 
     } 

    // keep going data.C through data.Z doing the exact same code 
    } 
} 

显然具有26个if语句只是为了确定一个属性null,然后更新该属性并执行数据库调用 可能在实现中非常天真。什么是做这个工作单位的更好方式?

+0

我以为我的代码很糟糕... – JonH

+3

介绍:http://codereview.stackexchange.com/ – Ray

+4

问题的根源在于有26个属性的类,称为A到Z.是否有理由它不是数组或字典什么的? – Ray

回答

3

谢天谢地C# is able to inspect and assign class members dynamically,所以一个选项将创建一个 地图 列表并迭代。

public string DataField(int id, string fieldName) 
    { 
     var data = _dataRepository.Find(id); 

     List<string> props = new List<string>(); 
     props.Add("A"); 
     props.Add("B"); 
     props.Add("C"); 

     if (data != null) 
     { 
      Type t = typeof(data).GetType(); 
      foreach (String entry in props) { 
       PropertyInfo pi = t.GetProperty(entry); 
       if (pi.GetValue(data) == null) { 
        pi.SetValue(data, fieldName); 
        _dataRepository.InsertOrUpdate(data); 
        return entry; 
       } 
      } 
     } 
    } 
+0

虽然我无法直接使用您的代码,但是PropertyInfo在对象上的查找使我们真正开始思考我们在做什么。经过多一点代码审查,我们实际上决定改变我们的数据方案,并以一种非常不同的方式攻击我们的问题,而不是使用“a”,“b”,“c”的设置......感谢您的洞察力。 – Chris

1

您可以循环遍历从'A'到'Z'的所有字符。这很难,因为你想访问你的'数据'对象的属性与相应的名称,但应该(据我所知)有可能通过C#反射功能。

当你摆脱了连续的if语句的这仍然不会让你的代码不错:P

+0

+1最后一句 – daniloquio

+1

当人们第一次告诉我反思时,我担心这些事情会发生......它就像内置的坏风格支持:D –

+1

完全同意,没有任何东西让代码看起来不错,所以我们继续前进,稍微回头看了一下,决定对基础数据方案进行一些更改。 – Chris

-1

注: - 如果数据是对象而不是结构,则不要使用。

我想到的是,如果A-Z都是同一类型,那么理论上你可以直接访问内存来检查非空值。

start = &data; 

for (i = 0; i < 26; i++){ 
    if ((typeof_elem) *(start + sizeof(elem)*i) != null){ 
     *(start + sizeof(elem)*i) = fieldName; 
     return (char) (65 + i); 
    } 
} 

未经测试,但给一个想法;)

+1

几乎没有危险,没有保存... – fixagon

+0

这是有风险的,但如果一切正常,将工作顺利。尽管如果数据是一个对象而不是结构体,那么这不是我必须承认的一个好方法。 – jancha

+0

其中,假定字段按顺序排列在对象(或结构)中。它也需要不安全的代码(你不显示)。而且,正如你所说,如果'data'是一个引用类型(很可能),它不会很好地工作。 –

0

由于你总是先设定最低字母表场和回报,你可以使用你的类,它跟踪的第一个可用字段中的附加字段。例如,这可以是一个整数lowest_alphabet_unset,只要你一组数据你会更新{X}:

初始化:

lowest_alphabet_unset = 0; 

数据场:

lowest_alphabet_unset ++; 
switch (lowest_alphabet_unset) { 

    case 1: 
     /* A is free */ 
     /* do something */ 
     return 'A'; 
    [...] 

    case 7: 
     /* A through F taken */ 
     data.G = fieldName; 
     _dataRepository.InsertOrUpdate(data); 
     return 'G'; 
    [...] 
} 
0
var data = _dataRepository.Find(id); 

如果可能的话,你应该使用另一个没有这26个属性的数据类型。新的DataType应该有1个属性,Find方法应该返回该新DataType的一个实例;那么,如果以更自然的方式,你可以摆脱26。

要返回 “A”, “B” ...... “Z”,你可以这样做:

return (char)65; //In this example this si an "A" 

,并与来自data.Value 65和90(A之间的一些转换为数字工作到Z)。

1

有您的问题使用反射看中LINQ的解决方案:

,但因为它是之前所说:你的数据结构是不是通过

public String DataField(int id, string fieldName) 
{ 
    var data = new { Z = "test", B="asd"}; 
    Type p = data.GetType(); 

    var value = (from System.Reflection.PropertyInfo fi 
        in p.GetProperties().OrderBy((fi) => fi.Name) 
        where fi.Name.Length == 1 && fi.GetValue(data, null) != null 
        select fi.Name).FirstOrDefault(); 
    return value; 
} 

非常深思熟虑TA taaaaaaaaa 像你得到的财产,但更新尚未完成。

+0

我真的很喜欢linq的方式潜入对象的属性和遍历每个项目的PropertyInfo。我继续努力尝试这一点,但发现我们的要求比我认为的面值更加棘手。感谢您的洞察力,并且您开始与我们进行新的对话,重新思考我们的数据方案以及我们课程之间的相互合作方式。 – Chris