Se você deseja uma lista fortemente tipada de tipos anônimos, também precisará tornar a lista um tipo anônimo. A maneira mais fácil de fazer isso é projetar uma sequência como uma matriz em uma lista, por exemplo,
var nodes =(new[]{new{Checked=false,/* etc */}}).ToList();
Então você poderá acessá-lo como:
nodes.Any(n => n.Checked);
Por causa da maneira como o compilador funciona, o seguinte também deve funcionar depois que você criar a lista, porque os tipos anônimos têm a mesma estrutura e também o mesmo tipo. Eu não tenho um compilador à mão para verificar isso.
Se você estiver armazenando o objeto como tipo object, precisará usar a reflexão. Isso vale para qualquer tipo de objeto, anônimo ou não. Em um objeto o, você pode obter seu tipo:
Type t = o.GetType();
Então, a partir disso, você pesquisa uma propriedade:
PropertyInfo p = t.GetProperty("Foo");
Depois disso, você pode obter um valor:
object v = p.GetValue(o,null);
Esta resposta está muito atrasada para uma atualização para C # 4:
dynamic d = o;object v = d.Foo;
E agora outra alternativa no C # 6:
object v = o?.GetType().GetProperty("Foo")?.GetValue(o,null);
Observe que, ao usar, ?.fazemos com que o resultado vocorra nullem três situações diferentes!
oé null, então não há nenhum objeto
oé não, nullmas não tem uma propriedadeFoo
otem uma propriedade, Foomas seu valor real é null.
Portanto, isso não é equivalente aos exemplos anteriores, mas pode fazer sentido se você quiser tratar os três casos da mesma forma.
Nunca usei uma dinâmica antes até agora, boa atualização para o .NET 4.0 #
Alan Alan
na solução c # 4, você receberá uma exceção de tempo de execução se a propriedade não existir ( object v = d.Foo), enquanto GetValue(o, null)será nulo se não existir.
usar o seguinte código
1
Não, GetPropertyretornará nulle GetValuelançará se for aprovado null, portanto o efeito geral é uma exceção. A versão do C # 4.0 oferece uma exceção mais descritiva.
Daniel Earwicker
4
Se você estiver usando dinâmico em uma montagem diferente da origem, precisará usar [InternalsVisibleTo] #
Sarath
2
@DanielEarwicker obrigado pela conclusão. Também se aplica a tipos anônimos. Como todas as propriedades geradas para tipos anônimos são internas.
Sarath
13
Você pode iterar sobre as propriedades do tipo anônimo usando Reflexão; veja se existe uma propriedade "Marcada" e, se houver, obtenha seu valor.
foreach(object o in nodes){Type t = o.GetType();PropertyInfo[] pi = t.GetProperties();foreach(PropertyInfo p in pi){if(p.Name=="Checked"&&!(bool)p.GetValue(o))Console.WriteLine("awesome!");}}
Se você precisa apenas de uma propriedade e já sabe o nome dela, não faz sentido passar por todas elas; basta usar GetProperty e GetValue. Além disso, System.out.println é Java, C # não ...
Chris Charabaruk
Opa, assim é, Chris! Um pouco embaraçoso ... resolvido agora.
glennkentwell
6
A resposta aceita descreve corretamente como a lista deve ser declarada e é altamente recomendada para a maioria dos cenários.
Mas me deparei com um cenário diferente, que também cobre a pergunta. E se você precisar usar uma lista de objetos existente, como ViewData["htmlAttributes"]no MVC ? Como você pode acessar suas propriedades (geralmente são criadas via new { @style="width: 100px", ... })?
Para esse cenário um pouco diferente, quero compartilhar com você o que descobri. Nas soluções abaixo, estou assumindo a seguinte declaração para nodes:
List<object> nodes =newList<object>();
nodes.Add(new{Checked=false,
depth =1,
id ="div_1"});
1. Solução com dinâmica
No C # 4.0 e versões superiores , você pode simplesmente converter para dinâmico e escrever:
if(nodes.Any(n =>((dynamic)n).Checked==false))Console.WriteLine("found not checked element!");
Nota: Isso está usando ligação tardia, o que significa que ele reconhecerá apenas em tempo de execução se o objeto não tiver uma Checkedpropriedade e dispara um RuntimeBinderExceptionnesse caso - portanto, se você tentar usar uma Checked2propriedade não existente , receberá a seguinte mensagem em tempo de execução:"'<>f__AnonymousType0<bool,int,string>' does not contain a definition for 'Checked2'" .
2. Solução com reflexão
A solução com reflexão funciona com versões antigas e novas do compilador C # . Para versões antigas do C #, considere a dica no final desta resposta.
fundo
Como ponto de partida, encontrei uma boa resposta aqui . A idéia é converter o tipo de dados anônimos em um dicionário usando reflexão. O dicionário facilita o acesso às propriedades, pois seus nomes são armazenados como chaves (você pode acessá-las como myDict["myProperty"]).
Inspirado pelo código no link acima, eu criei uma classe de extensão fornecendo GetProp, UnanonymizePropertiese UnanonymizeListItemscomo métodos de extensão, que o acesso simplificar a propriedades anónimos. Com essa classe, você pode simplesmente fazer a consulta da seguinte maneira:
if(nodes.UnanonymizeListItems().Any(n =>(bool)n["Checked"]==false)){Console.WriteLine("found not checked element!");}
ou você pode usar a expressão nodes.UnanonymizeListItems(x => (bool)x["Checked"] == false).Any()como ifcondição, que filtra implicitamente e depois verifica se há algum elemento retornado.
Para obter o primeiro objeto que contém a propriedade "Marcado" e retornar sua propriedade "profundidade", você pode usar:
var depth = nodes.UnanonymizeListItems()?.FirstOrDefault(n => n.Contains("Checked")).GetProp("depth");
ou mais curto: nodes.UnanonymizeListItems()?.FirstOrDefault(n => n.Contains("Checked"))?["depth"];
Nota: Se você possui uma lista de objetos que não contêm necessariamente todas as propriedades (por exemplo, alguns não contêm a propriedade "Verificado") e ainda deseja criar uma consulta com base nos valores "Verificados", é possível faça isso:
if(nodes.UnanonymizeListItems(x =>{var y =((bool?)x.GetProp("Checked",true));return y.HasValue&& y.Value==false;}).Any()){Console.WriteLine("found not checked element!");}
Isso impede que isso KeyNotFoundExceptionocorra se a propriedade "Marcado" não existir.
A classe abaixo contém os seguintes métodos de extensão:
UnanonymizeProperties: É usado para cancelar o anonimato das propriedades contidas em um objeto. Este método usa reflexão. Ele converte o objeto em um dicionário que contém as propriedades e seus valores.
UnanonymizeListItems: É usado para converter uma lista de objetos em uma lista de dicionários que contêm as propriedades. Opcionalmente, pode conter uma expressão lambda para filtrar previamente.
GetProp: É usado para retornar um valor único que corresponde ao nome da propriedade. Permite tratar propriedades não existentes como valores nulos (true) e não como KeyNotFoundException (false)
Para os exemplos acima, tudo o que é necessário é adicionar a classe de extensão abaixo:
publicstaticclassAnonymousTypeExtensions{// makes properties of object accessible publicstaticIDictionaryUnanonymizeProperties(thisobject obj){Type type = obj?.GetType();var properties = type?.GetProperties()?.Select(n => n.Name)?.ToDictionary(k => k, k => type.GetProperty(k).GetValue(obj,null));return properties;}// converts object list into list of properties that meet the filterCriteriapublicstaticList<IDictionary>UnanonymizeListItems(thisList<object> objectList,Func<IDictionary<string,object>,bool> filterCriteria=default){var accessibleList =newList<IDictionary>();foreach(object obj in objectList){var props = obj.UnanonymizeProperties();if(filterCriteria ==default|| filterCriteria((IDictionary<string,object>)props)==true){ accessibleList.Add(props);}}return accessibleList;}// returns specific property, i.e. obj.GetProp(propertyName)// requires prior usage of AccessListItems and selection of one element, because// object needs to be a IDictionary<string, object>publicstaticobjectGetProp(thisobject obj,string propertyName,bool treatNotFoundAsNull =false){try{return((System.Collections.Generic.IDictionary<string,object>)obj)?[propertyName];}catch(KeyNotFoundException){if(treatNotFoundAsNull)returndefault(object);elsethrow;}}}
Dica: O código acima está usando os nulos-condicional operadores, disponível desde C # versão 6.0 - Se você está trabalhando com compiladores mais antigos C # (por exemplo, C # 3.0), simplesmente substituir ?.por .e ?[por [toda a parte, por exemplo,
var depth = nodes.UnanonymizeListItems().FirstOrDefault(n => n.Contains("Checked"))["depth"];
Se você não for forçado a usar um compilador C # mais antigo, mantenha-o como está, pois o uso de condições nulas facilita muito o tratamento nulo.
Nota: Como a outra solução com dinâmico, esta solução também está usando ligação tardia, mas neste caso você não está recebendo uma exceção - ele simplesmente não encontrará o elemento se estiver se referindo a uma propriedade não existente, desde enquanto você mantém os operadores condicionais nulos .
O que pode ser útil para algumas aplicações é que a propriedade é referida por meio de uma string na solução 2, portanto, pode ser parametrizada.
object v = d.Foo
), enquantoGetValue(o, null)
será nulo se não existir.GetProperty
retornaránull
eGetValue
lançará se for aprovadonull
, portanto o efeito geral é uma exceção. A versão do C # 4.0 oferece uma exceção mais descritiva.Você pode iterar sobre as propriedades do tipo anônimo usando Reflexão; veja se existe uma propriedade "Marcada" e, se houver, obtenha seu valor.
Consulte esta postagem do blog: http://blogs.msdn.com/wriju/archive/2007/10/26/c-3-0-anonymous-type-and-net-reflection-hand-in-hand.aspx
Então, algo como:
fonte
A resposta aceita descreve corretamente como a lista deve ser declarada e é altamente recomendada para a maioria dos cenários.
Mas me deparei com um cenário diferente, que também cobre a pergunta. E se você precisar usar uma lista de objetos existente, como
ViewData["htmlAttributes"]
no MVC ? Como você pode acessar suas propriedades (geralmente são criadas vianew { @style="width: 100px", ... }
)?Para esse cenário um pouco diferente, quero compartilhar com você o que descobri. Nas soluções abaixo, estou assumindo a seguinte declaração para
nodes
:1. Solução com dinâmica
No C # 4.0 e versões superiores , você pode simplesmente converter para dinâmico e escrever:
Nota: Isso está usando ligação tardia, o que significa que ele reconhecerá apenas em tempo de execução se o objeto não tiver uma
Checked
propriedade e dispara umRuntimeBinderException
nesse caso - portanto, se você tentar usar umaChecked2
propriedade não existente , receberá a seguinte mensagem em tempo de execução:"'<>f__AnonymousType0<bool,int,string>' does not contain a definition for 'Checked2'"
.2. Solução com reflexão
A solução com reflexão funciona com versões antigas e novas do compilador C # . Para versões antigas do C #, considere a dica no final desta resposta.
fundo
Como ponto de partida, encontrei uma boa resposta aqui . A idéia é converter o tipo de dados anônimos em um dicionário usando reflexão. O dicionário facilita o acesso às propriedades, pois seus nomes são armazenados como chaves (você pode acessá-las como
myDict["myProperty"]
).Inspirado pelo código no link acima, eu criei uma classe de extensão fornecendo
GetProp
,UnanonymizeProperties
eUnanonymizeListItems
como métodos de extensão, que o acesso simplificar a propriedades anónimos. Com essa classe, você pode simplesmente fazer a consulta da seguinte maneira:ou você pode usar a expressão
nodes.UnanonymizeListItems(x => (bool)x["Checked"] == false).Any()
comoif
condição, que filtra implicitamente e depois verifica se há algum elemento retornado.Para obter o primeiro objeto que contém a propriedade "Marcado" e retornar sua propriedade "profundidade", você pode usar:
ou mais curto:
nodes.UnanonymizeListItems()?.FirstOrDefault(n => n.Contains("Checked"))?["depth"];
Nota: Se você possui uma lista de objetos que não contêm necessariamente todas as propriedades (por exemplo, alguns não contêm a propriedade "Verificado") e ainda deseja criar uma consulta com base nos valores "Verificados", é possível faça isso:
Isso impede que isso
KeyNotFoundException
ocorra se a propriedade "Marcado" não existir.A classe abaixo contém os seguintes métodos de extensão:
UnanonymizeProperties
: É usado para cancelar o anonimato das propriedades contidas em um objeto. Este método usa reflexão. Ele converte o objeto em um dicionário que contém as propriedades e seus valores.UnanonymizeListItems
: É usado para converter uma lista de objetos em uma lista de dicionários que contêm as propriedades. Opcionalmente, pode conter uma expressão lambda para filtrar previamente.GetProp
: É usado para retornar um valor único que corresponde ao nome da propriedade. Permite tratar propriedades não existentes como valores nulos (true) e não como KeyNotFoundException (false)Para os exemplos acima, tudo o que é necessário é adicionar a classe de extensão abaixo:
Dica: O código acima está usando os nulos-condicional operadores, disponível desde C # versão 6.0 - Se você está trabalhando com compiladores mais antigos C # (por exemplo, C # 3.0), simplesmente substituir
?.
por.
e?[
por[
toda a parte, por exemplo,Se você não for forçado a usar um compilador C # mais antigo, mantenha-o como está, pois o uso de condições nulas facilita muito o tratamento nulo.
Nota: Como a outra solução com dinâmico, esta solução também está usando ligação tardia, mas neste caso você não está recebendo uma exceção - ele simplesmente não encontrará o elemento se estiver se referindo a uma propriedade não existente, desde enquanto você mantém os operadores condicionais nulos .
O que pode ser útil para algumas aplicações é que a propriedade é referida por meio de uma string na solução 2, portanto, pode ser parametrizada.
fonte
Recentemente, tive o mesmo problema no .NET 3.5 (nenhuma dinâmica disponível). Aqui está como eu resolvi:
Adaptado de algum lugar no stackoverflow:
Agora retorne o objeto via cast:
fonte