2010-07-11 58 views
10

我有多個大對象,每個都有大約60個字符串。我必須修剪所有這些字符串,並且我想這樣做,而不必去this.mystring = this.mystring.Trim()。相反,我正在尋找一種方法來自動讓每個對象發現自己的字符串,然後執行操作。遍歷對象自己的字符串和修剪每個

我對反射有一點了解,但還不夠,但我認爲這是可能的?另外,我不確定這是否重要,但一些字符串屬性是隻讀的(只有一個getter),所以這些屬性將不得不被跳過。

幫助?

回答

14

嗯,很容易獲得所有的屬性,並找出哪些是字符串和可寫的。 LINQ使它更容易。

var props = instance.GetType() 
        .GetProperties(BindingFlags.Instance | BindingFlags.Public) 
        // Ignore non-string properties 
        .Where(prop => prop.PropertyType == typeof(string)) 
        // Ignore indexers 
        .Where(prop => prop.GetIndexParameters().Length == 0) 
        // Must be both readable and writable 
        .Where(prop => prop.CanWrite && prop.CanRead); 

foreach (PropertyInfo prop in props) 
{ 
    string value = (string) prop.GetValue(instance, null); 
    if (value != null) 
    { 
     value = value.Trim(); 
     prop.SetValue(instance, value, null); 
    } 
} 

您可能希望只設置的屬性,如果實際修剪有差別,以避免重複計算的複雜性 - 或者它可能不適合你是一個問題。

有改善必要時性能的各種方式 - 比如:

  • 只是緩存的相關屬性,每種類型的
  • 使用Delegate.CreateDelegate打造爲干將代表和setter
  • 可能使用表達樹,雖然我不知道他們是否會幫助這裏

我不會採取任何這些步驟,除非性能但e實際上是一個問題。

+0

我以爲屬性樹會自動緩存,如果不是在調試模式?我讀了幾次。這是不是真的? – Alex 2010-07-11 08:01:45

+1

在這種情況下,即使在4.0中,「表達式」也是一種痛苦;不過,將多個「動作」組合成一個代表會很好。 – 2010-07-11 08:01:54

+0

@Alex - * source *中的lambda表達式可以使用後臺代理字段來做一些聰明的事情。然而,在運行時,AFAIK並不是真正的手動編譯樹('Compile')。 – 2010-07-11 08:03:33

3

喜歡的東西:

foreach (PropertyInfo prop in obj.GetType().GetProperties(
     BindingFlags.Instance | BindingFlags.Public)) 
    { 
     if (prop.CanRead && prop.CanWrite && prop.PropertyType == typeof(string) 
      && (prop.GetIndexParameters().Length == 0)) // watch for indexers! 
     { 
      var s = (string)prop.GetValue(obj, null); 
      if (!string.IsNullOrEmpty(s)) s = s.Trim(); 
      prop.SetValue(obj, s, null); 
     } 
    } 
+0

無參數類型。GetProperties()'調用包含靜態屬性,我懷疑*不應該包含在這裏。 – 2010-07-11 07:57:11

+1

@Jon - 很好,謝謝。我不會提到'IsReadable'; p另外 - 你可能想檢查索引器。 – 2010-07-11 08:00:41

+0

@Marc:將修復:) – 2010-07-11 08:17:23

0

所以對這個有點擴大,我有一個列表的列表一個複雜的對象,我想遍歷和修剪所有的子串的對象以及。我正在發佈我在@Jon做的答案中所做的內容。我很好奇,如果有更好的方法去做,或者我錯過了一些明顯的事情。

我擁有的對象比這個更復雜,但它應該說明我在嘗試什麼。

public class Customer 
{ 
    public string Name { get; set; } 
    public List<Contact> Contacts { get; set; } 
} 

public class Contact 
{ 
    public string Name { get; set; } 
    public List<Email> EmailAddresses {get; set;} 
} 

public class Email 
{ 
    public string EmailAddress {get; set;} 
} 


    private void TrimWhitespace(object instance) 
    { 
     if (instance != null) 
     { 
      var props = instance.GetType() 
        .GetProperties(BindingFlags.Instance | BindingFlags.Public) 
       // Ignore indexers 
        .Where(prop => prop.GetIndexParameters().Length == 0) 
       // Must be both readable and writable 
        .Where(prop => prop.CanWrite && prop.CanRead); 

      foreach (PropertyInfo prop in props) 
      { 
       if (instance is IEnumerable) 
       { 
        foreach (var item in (IEnumerable)instance) 
        { 
         TrimWhitespace(item); 
        } 
       } 
       else if (prop.GetValue(instance, null) is string) 
       { 
        string value = (string)prop.GetValue(instance, null); 
        if (value != null) 
        { 
         value = value.Trim(); 
         prop.SetValue(instance, value, null); 
        } 
       } 
       else 
        TrimWhitespace(prop.GetValue(instance, null)); 
      } 
     } 
    } 

的思考?

1

不需要在道具循環中檢查IEnumerable,並且如果實際實例是IEnumerable,道具將被忽略。修復IEnumerable部分:

private void TrimWhitespace(object instance) 
{ 
    if (instance != null) 
    { 
     if (instance is IEnumerable) 
     { 
      foreach (var item in (IEnumerable)instance) 
      { 
       TrimWhitespace(item); 
      } 
     } 

     var props = instance.GetType() 
       .GetProperties(BindingFlags.Instance | BindingFlags.Public) 
      // Ignore indexers 
       .Where(prop => prop.GetIndexParameters().Length == 0) 
      // Must be both readable and writable 
       .Where(prop => prop.CanWrite && prop.CanRead); 

     foreach (PropertyInfo prop in props) 
     { 
      if (prop.GetValue(instance, null) is string) 
      { 
       string value = (string)prop.GetValue(instance, null); 
       if (value != null) 
       { 
        value = value.Trim(); 
        prop.SetValue(instance, value, null); 
       } 
      } 
      else 
       TrimWhitespace(prop.GetValue(instance, null)); 
     } 
    } 
}