2015-10-06 46 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; 
}