簡體   English   中英

通過反思訪問集合

[英]Accessing a Collection Through Reflection

有沒有辦法使用反射迭代(通過foreach優先)集合? 我正在使用反射迭代對象中的屬性,當程序到達一個集合類型時,我希望它迭代集合的內容並能夠訪問集合中的對象。

目前,我在所有屬性上都設置了屬性,並且在集合屬性上將IsCollection標志設置為true。 我的代碼檢查此標志,如果是,則使用反射獲取Type。 有沒有辦法在某個集合上以某種方式調用GetEnumerator或Items才能迭代這些項目?

我有這個問題,但我沒有使用反射,而是直接檢查它是否是IEnumerable。 所有的集合都實現了

if (item is IEnumerable)
{
    foreach (object o in (item as IEnumerable))
    {

    }
} else {
   // reflect over item
}

我嘗試使用與Darren建議類似的技術,但請注意,不只是集合實現了IEnumerable。 例如, string也是IEnumerable並將迭代字符。

這是一個小函數,我用來確定一個對象是否是一個集合(由於ICollection也是IEnumerable,它也是可枚舉的)。

    public bool isCollection(object o)
    {
        return typeof(ICollection).IsAssignableFrom(o.GetType())
            || typeof(ICollection<>).IsAssignableFrom(o.GetType());
    }

只需獲取屬性的值,然后將其轉換為IEnumerable。 這里有一些(未經測試的)代碼可以給你一個想法:

ClassWithListProperty obj = new ClassWithListProperty();
obj.List.Add(1);
obj.List.Add(2);
obj.List.Add(3);

Type type = obj.GetType();
PropertyInfo listProperty = type.GetProperty("List", BindingFlags.Public);
IEnumerable listObject = (IEnumerable) listProperty.GetValue(obj, null);

foreach (int i in listObject)
    Console.Write(i); // should print out 123

你可能做的最好的事情是檢查對象是否實現了某些集合接口 - 可能IEnumerable就是你所需要的。 然后,只需從對象調用GetEnumerator(),並使用IEnumerator.MoveNext()和IEnumerator.Current來處理集合。

如果集合沒有實現這些接口,這對你沒有幫助,但是如果是這樣的話,我認為它並不是真正的集合。

只是為了獲取信息可能是某人的幫助......我有一個有嵌套類的類和一些其他類的集合。 我想保存類的屬性值以及嵌套類和類集合。 我的代碼如下:

 public void LogObject(object obj, int indent)
    {
        if (obj == null) return;
        string indentString = new string(' ', indent);
        Type objType = obj.GetType();
        PropertyInfo[] properties = objType.GetProperties();

        foreach (PropertyInfo property in properties)
        {
            Type tColl = typeof(ICollection<>);
            Type t = property.PropertyType;
            string name = property.Name;


            object propValue = property.GetValue(obj, null); 
            //check for nested classes as properties
            if (property.PropertyType.Assembly == objType.Assembly)
            {
                string _result = string.Format("{0}{1}:", indentString, property.Name);
                log.Info(_result);
                LogObject(propValue, indent + 2);
            }
            else
            {
                string _result = string.Format("{0}{1}: {2}", indentString, property.Name, propValue);
                log.Info(_result);
            }

            //check for collection
            if (t.IsGenericType && tColl.IsAssignableFrom(t.GetGenericTypeDefinition()) ||
                t.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == tColl))
            {
                //var get = property.GetGetMethod();
                IEnumerable listObject = (IEnumerable)property.GetValue(obj, null);
                if (listObject != null)
                {
                    foreach (object o in listObject)
                    {
                        LogObject(o, indent + 2);
                    }
                }
            }
        }
    }

一個叫這個函數

LogObject(obj, 0);

但是,我的課程中有一些結構,我需要弄清楚如何獲得它們的值。 Moreoevr,我有一些好評。 我也需要獲得它們的價值......如果我更新我的代碼,我會發布。

使用反射時,您不一定使用該對象的實例。 您必須創建一個能夠遍歷對象屬性的該類型的實例。 因此,如果使用反射,請使用ConstructorInfo.Invoke()(?)方法創建新實例或指向該類型的實例。

一種相當簡單的方法是將對象類型轉換為集合並直接使用它。

如果您沒有使用對象的實例而是使用Type,則可以使用以下命令:

// type is IEnumerable
if (type.GetInterface("IEnumerable") != null)
{
}

我會看一下Type.FindInterfaces方法。 這可以過濾掉給定類型實現的接口。 如在PropertyInfo.PropertyType.FindInterfaces(filterMethod,filterObjects)中。 您可以按IEnumerable進行篩選,並查看是否返回任何結果。 MSDN在方法文檔中有一個很好的例子。

暫無
暫無

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

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