如何搜索各种类型的属性

时间:2015-10-06 16:01:05

标签: c# search reflection

我有一个名为Part的基类和类似WireConnector的派生类以及从Part继承的更多类。

现在我想实现一个搜索函数,搜索派生类的所有属性中的字符串。

如果需要,应该尝试将字符串转换为Property的类型。属性也可以是列表,应该在第一级搜索。

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的属性等等。有没有一种通用的搜索方式而不会抛出所有类型?

3 个答案:

答案 0 :(得分: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如果您正在处理自定义类型。

答案 1 :(得分: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;
}

答案 2 :(得分: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;
       }
   }