O código abaixo está funcionando bem, contanto que eu tenha aula ClassSameAssembly
na mesma montagem da classe Program
. Mas quando eu movo a classe ClassSameAssembly
para uma montagem separada, um RuntimeBinderException
(veja abaixo) é lançado. É possível resolver isso?
using System;
namespace ConsoleApplication2
{
public static class ClassSameAssembly
{
public static dynamic GetValues()
{
return new
{
Name = "Michael", Age = 20
};
}
}
internal class Program
{
private static void Main(string[] args)
{
var d = ClassSameAssembly.GetValues();
Console.WriteLine("{0} is {1} years old", d.Name, d.Age);
}
}
}
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
: 'objeto' não contém uma definição para 'Nome'
at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at ConsoleApplication2.Program.Main(String[] args) in C:\temp\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 23
dynamic
c#-4.0
anonymous-types
mehanik
fonte
fonte
Respostas:
Eu acredito que o problema é que o tipo anônimo é gerado como
internal
, então o fichário realmente não "sabe" sobre ele como tal.Tente usar ExpandoObject em vez disso:
Eu sei que é um tanto feio, mas é o melhor que consigo pensar no momento ... Não acho que você possa usar um inicializador de objeto com ele, porque embora seja fortemente tipado como
ExpandoObject
o compilador não saberá o que fazer com "Nome" e "Idade". Você pode ser capaz de fazer isso:mas isso não é muito melhor ...
Você poderia potencialmente escrever um método de extensão para converter um tipo anônimo a um expando com o mesmo conteúdo através de reflexão. Então você pode escrever:
Mas isso é horrível :(
fonte
return Build<ExpandoObject>.NewObject(Name:"Micheal", Age: 20);
object
ou em um tipo genérico (você pode exigir que seja uma classe ...) e verificar o tipo em tempo de execução.Você pode usar
[assembly: InternalsVisibleTo("YourAssemblyName")]
para tornar visíveis os internos da montagem.fonte
Encontrei um problema semelhante e gostaria de acrescentar à resposta de Jon Skeets que há outra opção. A razão pela qual descobri foi que percebi que muitos métodos de extensão no Asp MVC3 usam classes anônimas como entrada para fornecer atributos html (new {alt = "Image alt", style = "padding-top: 5px"} =>
De qualquer forma - essas funções usam o construtor da classe RouteValueDictionary. Eu mesmo tentei fazer isso e, com certeza, funciona - embora apenas o primeiro nível (usei uma estrutura de vários níveis). SO - no código seria:
ASSIM ... O que realmente está acontecendo aqui? Uma espiada dentro do RouteValueDictionary revela este código (valores ~ = o acima):
SO - usando TypeDescriptor.GetProperties (o), poderíamos obter as propriedades e valores apesar do tipo anônimo ser construído como interno em uma montagem separada! E, claro, isso seria muito fácil de estender para torná-lo recursivo. E fazer um método de extensão se você quiser.
Espero que isto ajude!
/Vencedor
fonte
Aqui está uma versão rudimentar de um método de extensão para ToExpandoObject que tenho certeza que tem espaço para polimento.
fonte
Uma solução mais limpa seria:
Que agora é um ExpandoObject.
Lembre-se de fazer referência:
fonte
Método de extensão ToExpando (mencionado na resposta de Jon) para os corajosos
fonte
A solução abaixo funcionou para mim em meus projetos de aplicativos de console
Coloque este [assembly: InternalsVisibleTo ("YourAssemblyName")] em \ Properties \ AssemblyInfo.cs do projeto separado com a função que retorna o objeto dinâmico.
"YourAssemblyName" é o nome do assembly do projeto de chamada. Você pode obter isso por meio de Assembly.GetExecutingAssembly (). FullName executando-o na chamada do projeto.
fonte
Se você já estiver usando Newtonsoft.Json em seu projeto (ou se estiver disposto a adicioná-lo para essa finalidade), poderá implementar aquele método de extensão horrível ao qual Jon Skeet se refere em sua resposta da seguinte maneira:
fonte