2015-10-06 48 views
3

我有一個基類Part和衍生類如WireConnector和更多從Part繼承。howto通過各種類型的屬性搜索

現在我想實現一個搜索函數,該函數可以搜索派生類的所有屬性中的字符串。

如果需要,應嘗試將字符串轉換爲屬性的類型。屬性也可以是列表,應該在第一級搜索。

class Part 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

class Wire : Part 
{ 
    public NumberWithUnit Diameter { get; set; } 
    public Weight Weight { get; set; } 
} 

class Connector : Part 
{ 
    public List<Part> ConnectedParts { get; set; } 
} 

我知道怎麼一般通過基本類型的屬性與反射搜索這樣

private bool SearchProperties<T>(T part, string searchString) where T : Part 
{ 
    var props = typeof(T).GetProperties(); 
    foreach (var prop in props) 
    { 
     var value = prop.GetValue(part); 
     if (value is string) 
     { 
      if (string.Equals(value, searchString)) 
       return true; 
     } 
     else if (value is int) 
     { 
      int v; 
      if (int.TryParse(searchString, out v)) 
      { 
       if(v == (int) value) 
        return true; 
      } 
     } 
    } 
    return false; 
} 

但是,這將是種很長的名單,我有Weight類型的屬性,例如,許多更多。有沒有一種通用的方式來搜索而不用投射所有類型?

+1

可能會有點麻煩,但是我認爲像'IStringSearchable'接口定義爲非原始類型會有所幫助。可能有更好的解決方案,但不需要觸及每個課程。 – ryanyuyu

+0

如果被檢查的對象包含複雜類型的屬性,是否也意味着檢查其屬性?我在問,因爲在這個問題中,你正在使用短語「派生**類的所有屬性」。 –

+0

派生類我的意思是從'Part'繼承的所有類。但是對於一個複雜的類型來說,檢查所有的屬性也是很好的,但是隻能這麼做。 –

回答

0

我會給你一個不同的想法來做到這一點。

你可以嘗試這樣的事情:

private bool SearchProperties<T, W>(T part, W searchValue) where T : Part 
    { 
     var props = typeof(T).GetProperties(); 
     foreach (var prop in props) 
     { 
      if (typeof(W) == prop.PropertyType) 
      { 
       var value = prop.GetValue(part, null); 

       if (searchValue.Equals(value)) 
        return true; 
      } 
     } 
     return false; 
    } 

你需要調用的方法是這樣的:

private void button12_Click(object sender, EventArgs e) 
    { 
     Part p = new Part(); 
     p.Id = 2; 
     p.Name = "test"; 
     p.bla = new Bla(); 

     SearchProperties<Part, int>(p, 2); 
    }  

如果你需要比較複雜的屬性(重量,...)通過與GetHashCode不同的方式,您可以覆蓋方法Equals==運算符。

class Weight 
    { 
     public int Id { get; set; } 

     public override bool Equals(object obj) 
     { 
      return Id == ((Weight)obj).Id; 
     } 
    } 
+0

這不符合要求:一個給定的搜索字符串應該搜索對象上的所有*屬性。 – StriplingWarrior

2

考慮與您的轉換方向相反。而不是你的搜索字符串轉換爲每個可能值,只是轉換值轉換成字符串:

private bool SearchProperties<T>(T part, string searchString) where T : Part 
{ 
    var props = typeof(T).GetProperties(); 
    foreach (var prop in props) 
    { 
     var value = prop.GetValue(part); 
     if (value is IEnumerable) 
     { 
      // special handling for collections 
     } 
     else if(value != null) 
     { 
      string valueString = value.ToString(); 
      if (string.Equals(valueString, searchString)) 
       return true; 
     } 
    } 
    return false; 
} 

而且工作得很好大多數內置類型,你必須做的唯一的事情得到它的工作Weight等是確保他們執行ToString()

另一種解決方案是使用TypeDescriptor:

private bool SearchProperties<T>(T part, string searchString) where T : Part 
{ 
    var props = typeof(T).GetProperties(); 
    foreach (var prop in props) 
    { 
     var value = prop.GetValue(part); 
     if (value is IEnumerable) 
     { 
      // special handling for collections 
     } 
     else if(value != null) 
     { 
      object searchValue = null; 
      try 
      { 
       searchValue = TypeDescriptor.GetConverter(value).ConvertFromString(searchString); 
      } catch {} 
      if (searchValue != null && object.Equals(value, searchValue)) 
       return true; 
     } 
    } 
    return false; 
} 

TypeDescriptor對於大多數內置類型的效果很好,但如果你正在處理自定義類型requires extra work

+0

它不適用於複雜的對象。 –

+0

@OnlyaCuriousMind:如果他們實現了'ToString()' – StriplingWarrior

+0

當然:D這也是一個好方法。 –

1

我認爲以下應覆蓋大部分的實際情況:

public static bool SearchProperties(object target, string searchString) 
{ 
    if (target == null) return false; 
    // Common types 
    var convertible = target as IConvertible; 
    if (convertible != null) 
    { 
     var typeCode = convertible.GetTypeCode(); 
     if (typeCode == TypeCode.String) return target.ToString() == searchString; 
     if (typeCode == TypeCode.DBNull) return false; 
     if (typeCode != TypeCode.Object) 
     { 
      try 
      { 
       var value = Convert.ChangeType(searchString, typeCode); 
       return target.Equals(value); 
      } 
      catch { return false; } 
     } 
    } 
    if (target is DateTimeOffset) 
    { 
     DateTimeOffset value; 
     return DateTimeOffset.TryParse(searchString, out value) && value == (DateTimeOffset)target; 
    } 
    var enumerable = target as IEnumerable; 
    if (enumerable != null) 
    { 
     // Collection 
     foreach (var item in enumerable) 
      if (SearchProperties(item, searchString)) return true; 
    } 
    else 
    { 
     // Complex type 
     var properties = target.GetType().GetProperties(); 
     foreach (var property in properties) 
     { 
      if (property.GetMethod == null || property.GetMethod.GetParameters().Length > 0) continue; 
      var value = property.GetValue(target); 
      if (SearchProperties(value, searchString)) return true; 
     } 
    } 
    return false; 
}