dinâmico não contém uma definição para uma propriedade de uma referência de projeto

91

Estou recebendo um erro que diz:

'objeto' não contém uma definição para 'Título'

todo o código também está no github

Eu tenho um ConsoleApplication1 que se parece com este

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Movie m = new Movie();
            var o = new { Title = "Ghostbusters", Rating = "PG" };
            Console.WriteLine(m.PrintMovie(o));
        }
    }
} 

e Movie.cs

public class Movie : DynamicObject
{
    public string PrintMovie(dynamic o)
    {
        return string.Format("Title={0} Rating={1}", o.Title, o.Rating);
    }
} 

funciona bem no MESMO projeto, mas se eu adicionar ConsoleApplication2 com uma referência a ConsoleApplication1 e adicionar o mesmo código exato

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            Movie m = new Movie();
            var o = new { Title = "Ghostbusters", Rating = "PG" };
            Console.WriteLine(m.PrintMovie(o));
        }
    }
}

Recebo um erro:

'objeto' não contém uma definição para 'Título' **

mesmo que esteja no objeto dinâmico.

  • o.Title 'o.Title' gerou uma exceção do tipo 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' dynamic {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}

Aqui está uma captura de tela: insira a descrição da imagem aqui

Estou fazendo algo assim e tentando chamar a função de filme de um projeto de teste.

eiu165
fonte

Respostas:

79

Você precisa usar um ExpandoObject

 dynamic o = new ExpandoObject();
 o.Title = "Ghostbusters";
 o.Rating = "PG";

 Console.WriteLine(m.PrintMovie(o));
JamahalSOF
fonte
28
Ele teve muitos problemas para escrever uma pergunta elaborada, seria bom informá-lo por que ele está recebendo o erro, como sugere Robert
Luis Ferrao
2
Não parece que você pode usar a funcionalidade do inicializador embutido com o objeto expando?
Roberto Bonini
1
Onde devo usar ExpandoObject? para criar um objeto dinâmico ou para analisar um objeto dinâmico?
Hosein Aqajani
Tive que procurar mais informações, pois a resposta de Robert foi útil, mas precisava de um entendimento mais profundo. Oreilly teve um bom artigo sobre tipos dinâmicos aqui: oreilly.com/learning/building-c-objects-dynamically
Billy Willoughby
137

A resposta de Jahamal não diz por que você obteve o erro. O motivo é que a classe anônima é internalpara a montagem. A palavra-chave dynamicnão permite que você ignore a visibilidade do membro.

A solução é substituir a classe anônima pela classe pública nomeada.

Aqui está outro bom exemplo que explica o motivo e outra solução possível .

O motivo da data2.Personfalha na chamada é que as informações de tipo de data2não estão disponíveis no tempo de execução. O motivo de não estar disponível é porque os tipos anônimos não são públicos. Quando o método está retornando uma instância desse tipo anônimo, ele está retornando um System.Object que faz referência a uma instância de um tipo anônimo - um tipo cujas informações não estão disponíveis para o programa principal. O tempo de execução dinâmico tenta encontrar uma propriedade chamada Personno objeto, mas não consegue resolvê-la a partir das informações de tipo que possui. Como tal, ele lança uma exceção. A chamada data.Namefunciona bem por Personser uma aula pública, essa informação está disponível e pode ser facilmente resolvida.

Isso pode afetar você em qualquer um dos seguintes casos (se não mais):

  1. Você está retornando um tipo não público e não interno usando System.Object. 2. Você está retornando um tipo derivado não público e não interno por meio de um tipo base público e acessando uma propriedade no tipo derivado que não está no tipo base. 3. Você está retornando qualquer coisa dentro de um tipo anônimo de um assembly diferente.
Robert Važan
fonte
1
Você poderia citar sua fonte em sua resposta, por favor?
d3dave
@ d3dave As duas afirmações da resposta podem ser testadas. A visibilidade da classe pode ser verificada no decompilador .NET. As regras de acesso para dynamicpodem ser verificadas em uma classe de teste com membros de visibilidade variável.
Robert Važan
3
Esta é a verdadeira resposta para explicar por que o que OP estava fazendo é um problema.
Matti Virkkunen
1
Não consigo fazer isso funcionar entre um projeto de origem e um projeto de teste que são ambos netcoreapp1.1. Alguma ideia se é só minha culpa ou se isso não funciona no .NET Core?
Anthony Mastrean 01 de
27

No meu caso, tive um projeto de Teste de Unidade que criei no Visual Studio e vários casos em que precisei testar métodos em uma biblioteca de camada de dados. Eu não queria mudar todos eles, então marquei a montagem de teste como um amigo usando:

[assembly:InternalsVisibleTo("MyDataLayerAssemblyName")]

E isso resolveu.

Exemplo:

using System.Runtime.CompilerServices;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[assembly: InternalsVisibleTo( "MyDataLayerAssembly" )]
namespace MyUnitTestProject.DataTests
{

   [TestClass]
   public class ContactTests
   {
      ...

Referências:

Jelgab
fonte
1
A razão é o que Alexander Stepaniuk disse. Seu comentário é a solução. Obrigado!
Pato Loco
Não consigo fazer isso funcionar entre projetos netcoreapp1.1, não tenho certeza se é algo que estou fazendo incorretamente.
Anthony Mastrean 01 de
Muito obrigado Jelgab! Agora não preciso substituir dynamic pelo ExpanoObject! Estou usando injeção de dependência em meus testes de unidade e não consegui usar dinâmico e fazê-lo funcionar a partir do projeto de teste de unidade. Mas isso resolveu!
ShameWare de
Observe que você (o desenvolvedor) deve adicionar isso no projeto oposto a partir do qual os tipos anônimos estão sendo criados, ou ambos, se for o caso.
ryanwebjackson de
0

No meu caso, tenho um projeto de teste xUnit.

Onde 'conteúdo' é uma string json .

Este código gera erro:

dynamic parsed = JsonConvert.DeserializeObject<dynamic>(content);

Este código funciona. Use ExpandoObject em vez de dinâmico como este:

dynamic parsed = JsonConvert.DeserializeObject<ExpandoObject>(content);
Guilherme Ferreira
fonte