2015-04-23 72 views
13

我有以下代碼:修改多個字符串字段

class SearchCriteria 
    { 
     public string Name { get; set; } 
     public string Email { get; set; } 
     public string Company { get; set; } 
     // ... around 20 fields follow 

     public void Trim() 
     { 
      if(! String.IsNullOrEmpty(Name)) 
      { 
       Name = Name.Trim(); 
      } 

      if(! String.IsNullOrEmpty(Email)) 
      { 
       Email = Email.Trim(); 
      } 

      // ... repeat for all 20 fields in the class. 
     } 
    } 

我想要寫一個函數,將適當修剪等領域,是這樣的:

public void Trim() 
{ 
    Trim(Name); 
    Trim(Email); 
    // ... 
} 

private static void Trim(ref string field) 
{ 
    if(! String.IsNullOrEmpty(field)) 
    { 
     field = field.Trim(); 
    } 
} 

當然,這是不允許的在C#中。 我有一個選擇是寫一個幫手,並使用反射。 有沒有另外一種方法可以實現這一點(反映在如此多的屬性上會有一定的性能影響,並且我無法承受這種情況)?

+7

也許你可以在他們各自的屬性設置器中修剪字符串? –

+2

我可能會重新設計整個類來使用HashMap來保存20個不同的字符串值,因爲它們看起來是可選屬性列表。然後你有一個PUT方法,可以進行修整。 – Falco

+0

@Falco:你怎麼知道所有的都是字符串?可能有'DateTime DayOfBirth'。使用'List '會太抽象,因爲你不能說:給我'SearchCriteria.Email'了。如果你使用'Dictionary ',你必須知道密鑰。 –

回答

11

如果你已經有了代碼,你在問什麼?它的可讀性和高效性。但是也許最好讓這些屬性已經在第一個地方修整傳遞的值。

class SearchCriteria 
{ 
    private string _Name; 
    public string Name 
    { 
     get { return _Name; } 
     set { _Name = value == null ? null : value.Trim(); } 
    } 

    private string _Email; 
    public string Email 
    { 
     get { return _Email; } 
     set { _Email = value == null ? null : value.Trim(); } 

    } 

    private string _Company; 
    public string Company 
    { 
     get { return _Company; } 
     set { _Company = value == null ? null : value.Trim(); } 

    } 

    // ... around 20 fields follow 
} 

即使您可以使用反射方法。考慮到這個代碼總是很難理解和維護。即使它們不應該被修剪,它也會默默修剪屬性。例如,如果其他開發人員擴展了這個類。

6
public void Trim() 
{ 
    Name = Trim(Name); 
    Email = Trim(Email); 
    // ... 
} 

private string Trim(string field) 
{ 
    if(! String.IsNullOrEmpty(field)) 
     field = field.Trim(); 
    return field; 
} 

編輯:

嘗試也適用Trim機能的研究中性能的制定者

class SearchCriteria 
{  
    private string Trim(string field) 
    { 
     if(! String.IsNullOrEmpty(field)) 
      field = field.Trim(); 
     return field; 
    } 

    private string _name; 
    public string Name 
    { 
     get { return _name; } 
     set { _name = Trim(value); } 
    } 

    private string _email; 
    public string Email 
    { 
     get { return _email; } 
     set { _email = Trim(value); } 

    } 

    // ... other string properties 
    // no public void Trim() method 
} 
3

似乎矯枉過正..節省的時間在Trim(),浪費在字段聲明時

class SearchCriteria 
{ 
    private Dictionary<string, string> _internalValues = new Dictionary<string, string>(); 
    public string Name { get { return _internalValues.ContainsKey("Name") ? _internalValues["Name"] : null; } set { _internalValues["Name"] = value; } } 
    .... 

    public void Trim() 
    { 
     foreach (var entry in _internalValues) 
     { 
      if (!string.IsNullOrEmpty(entry.Value)) _internalValues[entry.Key] = entry.Value.Trim(); 
     } 
    } 
} 
+0

如果沒有傳統的理由,爲什麼類的公共接口必須保持不變,我將廢除整個訪問器,並簡單地執行SearchCriteria.get(SCEnum.Email); – Falco

2

你可以修改你的代碼,如下所示

public void Trim() 
{ 
    Name = Trim(Name); 
    Email = Trim(Email); 
    // ... 
} 

private static void Trim(string field) 
{ 
    if(! String.IsNullOrWhiteSpace(field)) 
    { 
     field = field.Trim(); 
    } 

    return field; 
} 

您無法通過引用傳遞屬性和方法String.IsNullOrEmpty()會考慮空白非空的,所以我用String.IsNullOrWhiteSpace()

2

剛剛完成。我不知道這是否是一個好方法。但你可以像Tim Schmelter說的那樣反思。但正如他也指出,代碼難以維護,如果有人擴展它可能是問題。但這裏是你如何能做到這一點的例子:

class SearchCriteria 
{ 
    public string Name { get; set; } 
    public string Email { get; set; } 
    public string Company { get; set; } 
    // ... around 20 fields follow 

    public void Trim() 
    { 
     typeof(SearchCriteria).GetProperties() 
      .Where (w =>w.PropertyType==typeof(string)) 
      .ToList().ForEach(f=> 
      { 
       var value=f.GetValue(this); 
       if(value!=null && !string.IsNullOrEmpty(value.ToString())) 
       { 
        f.SetValue(this,value.ToString().Trim(),null); 
       } 
      }); 
    } 
} 
3

我喜歡這種風格,重複是不可避免的,以保持可讀性,但是這將節省一些屏幕空間

class SearchCriteria 
{ 
    public string Name { get; set; } 
    public string Email { get; set; } 
    public string Company { get; set; } 


    public void Trim() 
    { 
     if(!String.IsNullOrEmpty(Name)) Name = Name.Trim(); 
     if(!String.IsNullOrEmpty(Email)) Email = Email.Trim(); 
     if(!String.IsNullOrEmpty(Company)) Company = Company.Trim(); 
    } 
} 

void Main() 
{ 
    var criteria = new SearchCriteria(); 
    criteria.Email = "thing "; 
    Console.WriteLine(criteria.Email.Length); 
    criteria.Trim(); 
    Console.WriteLine(criteria.Email); 
    Console.WriteLine(criteria.Email.Length); 
} 
2

的反思顯然會不是最高性能的解決方案,但是仍然可以使用一些修改和緩存。

這裏是反射幫手,讓您創建突變代表的收集,並將它緩存類的內部:

public static class ReflectionHelper 
{ 
    public static IEnumerable<PropertyInfo> GetPropertiesOfType<THolder, TPropType>() 
    { 
     return typeof(THolder).GetPropertiesOfType(typeof(TPropType)); 
    } 


    public static IEnumerable<PropertyInfo> GetPropertiesOfType(this Type holderType, Type propType) 
    { 
     if (holderType == null) 
      throw new ArgumentNullException("holderType"); 
     if (propType == null) 
      throw new ArgumentNullException("propType"); 

     return holderType 
      .GetProperties() 
      .Where(prop => 
       prop.PropertyType == propType); 
    } 


    public static IEnumerable<Action<Func<TPropType, TPropType>>> CreateMutators<THolder, TPropType>(THolder holder) 
    { 
     if (holder == null) 
      throw new ArgumentNullException("holder"); 

     return holder.GetType() 
      .GetPropertiesOfType(typeof(TPropType)) 
      .Select(prop => 
       new 
       { 
        getDelegate = (Func<TPropType>)Func.CreateDelegate(
         typeof(Func<TPropType>), 
         holder, 
         prop.GetGetMethod()), 
        setDelegate = (Action<TPropType>)Action.CreateDelegate(
         typeof(Action<TPropType>), 
         holder, 
         prop.GetSetMethod()) 
       }) 
      .Select(accessor => 
       (Action<Func<TPropType, TPropType>>)((mutate) => 
       { 
        var original = accessor.getDelegate(); 
        var mutated = mutate(original); 
        accessor.setDelegate(mutated); 
       })) 
      .ToArray(); 
    } 
} 

類代碼 - 您緩存的存取器和使用它們的修剪方法中:

class SearchCriteria 
{ 
    public SearchCriteria() 
    { 
     this.Name = "adsfasd  "; 
     this.Email = "  adsfasd  "; 
     this.Company = " asdf adsfasd  "; 

     this.stringMutators = ReflectionHelper.CreateMutators<SearchCriteria, String>(this); 
    } 

    public string Name { get; set; } 
    public string Email { get; set; } 
    public string Company { get; set; } 
    // ... around 20 fields follow 

    private IEnumerable<Action<Func<String, String>>> stringMutators; 


    private String TrimMutate(String value) 
    { 
     if (String.IsNullOrEmpty(value)) 
      return value; 

     return value.Trim(); 
    } 

    public void Trim() 
    { 
     foreach (var mutator in this.stringMutators) 
     { 
      mutator(this.TrimMutate); 
     } 
    } 

    public override string ToString() 
    { 
     return String.Format("Name = |{0}|, Email = |{1}|, Company = |{2}|", 
      this.Name, 
      this.Email, 
      this.Company); 
    } 
} 

主代碼:

  var criteria = new SearchCriteria(); 

      Console.WriteLine("Before trim:"); 
      Console.WriteLine(criteria); 


      Console.WriteLine("After trim:"); 
      criteria.Trim(); 
      Console.WriteLine(criteria); 

P。:然而,這不是一個非常直接或清晰的解決方案,所以我建議像「其他答案」中描述的那樣,使用「智能」setter(getter)。或者,也許你可以嘗試一些Aspect Oriented Programming approach

3

如果你不使用自動屬性,你可以使用ref。我同意這絕不是最佳的。

class SearchCriteria 
{ 
    private string _name; 
    public string Name { get { return _name; } set { _name = value; }} 
    public string Email { get; set; } 
    public string Company { get; set; } 
    // ... around 20 fields follow 

    void Trim(ref string str) 
    { 
     if (!String.IsNullOrEmpty(str)) 
     { 
      str = str.Trim(); 
     } 
    } 

    public void Trim() 
    { 
     Trim(ref _name); 

     // ... repeat for all 20 fields in the class. 
    } 
}