簡體   English   中英

如何搜索各種類型的屬性

[英]Howto search through Properties of all kinds of types

我有一個名為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屬性,例如,還有更多。 有沒有一種通用的搜索方式而不會拋出所有類型?

考慮與轉換相反的方向。 不要將搜索字符串轉換為每個可能的值,只需將值轉換為字符串:

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適用於大多數內置類型,但如果您正在處理自定義類型,則需要額外的工作

我認為以下內容應涵蓋大多數實際情況:

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;
}

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

你可以嘗試這樣的事情:

 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不同的方式比較復雜屬性(Weight,...),則可以覆蓋方法Equals==運算符。

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM