dinámico no contiene una definición para una propiedad de una referencia de proyecto

93

Recibo un error que dice:

'objeto' no contiene una definición de 'Título'

todo el código también está activado github

Tengo una ConsoleApplication1 que se ve así

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

y Movie.cs

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

funciona bien desde el MISMO proyecto, pero si agrego ConsoleApplication2 con una referencia a ConsoleApplication1 y agrego exactamente el mismo código

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

Me sale un error:

'objeto' no contiene una definición de 'Título' **

aunque esté en el objeto dinámico.

  • o.Title 'o.Title' arrojó una excepción de tipo 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' dynamic {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}

Aquí hay una captura de pantalla: ingrese la descripción de la imagen aquí

Estoy haciendo algo como esto e intento llamar a la función de película desde un proyecto de prueba.

eiu165
fuente

Respuestas:

79

Necesitas usar un ExpandoObject

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

 Console.WriteLine(m.PrintMovie(o));
JamahalSOF
fuente
28
Pasó por muchos problemas para escribir una pregunta elaborada, sería bueno haberle hecho saber por qué recibe el error, como sugiere Robert
Luis Ferrao
2
¿No parece que pueda usar la funcionalidad del inicializador en línea con el objeto expando?
Roberto Bonini
1
¿Dónde debería usar ExpandoObject? para crear un objeto dinámico o para analizar un objeto dinámico?
Hosein Aqajani
Tuve que buscar más información ya que la respuesta de Robert fue útil, pero necesitaba una comprensión más profunda. Oreilly tenía un buen artículo sobre tipos dinámicos aquí: oreilly.com/learning/building-c-objects-dynamically
Billy Willoughby
139

La respuesta de Jahamal no dice por qué aparece el error. La razón es que la clase anónima es internalpara la asamblea. Palabra clavedynamic no le permite eludir la visibilidad de los miembros.

La solución es reemplazar la clase anónima con una clase pública nombrada.

Aquí hay otro buen ejemplo que explica el motivo y otra posible solución .

La razón por la que data2.Personfalla la llamada a es que la información de tipo de data2no está disponible en tiempo de ejecución. La razón por la que no está disponible es porque los tipos anónimos no son públicos. Cuando el método devuelve una instancia de ese tipo anónimo, devuelve una System.Object que hace referencia a una instancia de un tipo anónimo, un tipo cuya información no está disponible para el programa principal. El tiempo de ejecución dinámico intenta encontrar una propiedad llamada Personen el objeto, pero no puede resolverla a partir de la información de tipo que tiene. Como tal, lanza una excepción. La llamada a data.Namefunciona bien ya que Persones una clase pública, esa información está disponible y se puede resolver fácilmente.

Esto puede afectarle en cualquiera de los siguientes casos (si no más):

  1. Está devolviendo un tipo no público, no interno usando System.Object. 2. Devuelve un tipo derivado no público, no interno a través de un tipo base público y accede a una propiedad en el tipo derivado que no está en el tipo base. 3. Está devolviendo cualquier cosa envuelta dentro de un tipo anónimo de un ensamblado diferente.
Robert Važan
fuente
1
¿Podría citar su fuente en su respuesta, por favor?
d3dave
@ d3dave Las dos afirmaciones de la respuesta pueden probarse. La visibilidad de la clase se puede comprobar en el decompilador de .NET. Las reglas de acceso para dynamicse pueden verificar en una clase de prueba con miembros de diferente visibilidad.
Robert Važan
3
Esta es la respuesta real a por qué lo que OP estaba haciendo es un problema.
Matti Virkkunen
1
No puedo hacer que esto funcione entre una fuente y un proyecto de prueba que son netcoreapp1.1. ¿Alguna idea de si es solo mi culpa o si esto no funciona en .NET Core?
Anthony Mastrean
29

En mi caso, tuve un proyecto de prueba unitaria que creé en Visual Studio y muchos casos en los que necesitaba probar métodos en una biblioteca de capas de datos. No quería cambiarlos todos, así que marqué el ensamblaje de prueba como amigo usando:

[assembly:InternalsVisibleTo("MyDataLayerAssemblyName")]

Y eso lo resolvió.

Ejemplo:

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

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

   [TestClass]
   public class ContactTests
   {
      ...

Referencias:

Jelgab
fuente
1
La razón es lo que dijo Alexander Stepaniuk. Tu comentario es la solución. ¡Gracias!
Pato Loco
No puedo hacer que esto funcione entre proyectos netcoreapp1.1, no estoy seguro de si es algo que estoy haciendo incorrectamente.
Anthony Mastrean
¡Muchas gracias Jelgab! ¡Ahora no tengo que reemplazar dynamic con ExpanoObject! Estoy usando la inyección de dependencia en mis pruebas unitarias y no pude usar dinámica y hacer que funcione desde el proyecto de prueba unitaria. ¡Pero esto lo resolvió!
ShameWare
Tenga en cuenta que usted (el desarrollador) tiene que agregar esto en el proyecto opuesto desde el cual se están creando los tipos anónimos, o ambos, si ese es el caso.
ryanwebjackson
0

En mi caso, tengo un proyecto de prueba xUnit.

Donde 'contenido' es una cadena json .

Este código arroja un error:

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

Este código funciona. Use ExpandoObject en lugar de una dinámica como esta:

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