Pergunta

Existe uma forma de interagir (através foreach preferência) ao longo de uma coleção usando a reflexão? Estou interagindo sobre as propriedades em um objeto usando reflexão, e quando o programa chega a um tipo que é uma coleção, eu gostaria que iterar sobre o conteúdo da coleção e ser capaz de acessar os objetos na coleção.

No momento eu tenho um conjunto de atributos em todas as minhas propriedades, com uma bandeira IsCollection conjunto para true nas propriedades que são coleções. Meus código verifica para esta bandeira e se é verdade, ele obtém o tipo usando a reflexão. Existe uma maneira de chamar GetEnumerator ou Itens de alguma forma em uma coleção para ser capaz de repetir os itens?

Foi útil?

Solução

Eu tive esse problema, mas em vez de usar reflexão, acabei apenas verificar se era IEnumerable. Todas as coleções implementar isso.

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

    }
} else {
   // reflect over item
}

Outras dicas

Eu tentei usar uma técnica semelhante como Darren sugeriu, no entanto apenas cuidado para que não apenas coleções implementar IEnumerable. string por exemplo, é também IEnumerable e irá iterar sobre os personagens.

Aqui está uma pequena função que estou usando para determinar se um objeto é uma coleção (que será enumeráveis ??bem desde ICollection é também IEnumerable).

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

Apenas obter o valor da propriedade e, em seguida, lançá-lo em um IEnumerable. Aqui está um código (não testado) para lhe dar uma idéia:

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

O melhor que você provavelmente poderia fazer seria a de verificar se o objeto implementa determinadas interfaces de coleta - provavelmente IEnumerable seria tudo o que você precisa. Então é só uma questão de chamar GetEnumerator () fora do objeto, e usando IEnumerator.MoveNext () e IEnumerator.Current para trabalhar o seu caminho através da coleção.

Isso não vai ajudá-lo se a coleção não implementar essas interfaces, mas se esse for o caso, não é realmente muito de uma coleção, eu suponho.

Apenas para informação pode ser que será de ajuda de alguém ... Eu tive uma classe com classes aninhadas e coleta de algumas outras classes. Eu queria salvar os valores de propriedade da classe como classes bem aninhados e coleção de classes. Meu código é o seguinte:

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

Uma chamada esta função

LogObject(obj, 0);

No entanto, tenho algumas estruturas dentro das minhas aulas e eu preciso descobrir como obter os seus valores. Moreoevr, eu tenho alguma lista. Eu preciso para obter o seu valor bem .... Vou postar se eu atualizar meu código.

Quando seu uso de reflexão você não está necessariamente usando uma instância desse objeto. Você teria que criar uma instância desse tipo de poder para percorrer as propriedades do objeto. Então, se você estiver usando reflexão uso do ConstructorInfo.Invoke () (?) Para criar uma nova instância ou apontar para uma instância do tipo.

Eu olhava para o método Type.FindInterfaces. Isso pode filtrar as interfaces implementadas por um determinado tipo. Como em PropertyInfo.PropertyType.FindInterfaces (filterMethod, filterObjects). Você pode filtrar por IEnumerable e ver se quaisquer resultados são retornados. MSDN tem um grande exemplo na documentação do método.

Se você não estiver usando uma instância do objeto, mas sim um tipo, você pode usar o seguinte:

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

Uma abordagem bastante simples seria a conversão de tipo do objeto como a recolha e usar diretamente disso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top