dynamic ne contient pas de définition pour une propriété à partir d'une référence de projet

91

J'obtiens une erreur qui dit:

«objet» ne contient pas de définition pour «titre»

tout le code est aussi sur github

J'ai une ConsoleApplication1 qui ressemble à ceci

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

et Movie.cs

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

cela fonctionne bien à partir du même projet, mais si j'ajoute ConsoleApplication2 avec une référence à ConsoleApplication1 et ajoute le même code exact

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

J'obtiens une erreur:

'objet' ne contient pas de définition pour 'titre' **

même si c'est dans l'objet dynamique.

  • o.Title 'o.Title' a lancé une exception de type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' dynamic {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}

Voici une capture d'écran: entrez la description de l'image ici

Je fais quelque chose comme ça et j'essaie d'appeler la fonction film à partir d'un projet de test.

eiu165
la source

Réponses:

79

Vous devez utiliser un ExpandoObject

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

 Console.WriteLine(m.PrintMovie(o));
JamahalSOF
la source
28
Il a eu beaucoup de mal à écrire une question élaborée, ce serait bien de lui avoir fait savoir pourquoi il a l'erreur, comme le suggère Robert
Luis Ferrao
2
Vous ne semblez pas pouvoir utiliser la fonctionnalité d'initialisation en ligne avec l'objet expando?
Roberto Bonini
1
Où utiliser ExpandoObject? pour créer un objet dynamique ou pour analyser un objet dynamique?
Hosein Aqajani le
J'ai dû chercher plus d'informations car la réponse de Robert était utile mais j'avais besoin d'une compréhension plus profonde. Oreilly avait un bon article sur les types dynamiques ici: oreilly.com/learning/building-c-objects-dynamically
Billy Willoughby
137

La réponse de Jahamal ne dit pas pourquoi vous obtenez l'erreur. La raison en est que la classe anonyme est internalà l'assembly. Le mot clé dynamicne vous permet pas de contourner la visibilité des membres.

La solution consiste à remplacer la classe anonyme par la classe publique nommée.

Voici un autre bon exemple expliquant la raison et une autre solution possible .

La raison pour laquelle l'appel data2.Personéchoue est que les informations de type de data2ne sont pas disponibles au moment de l'exécution. La raison pour laquelle il n'est pas disponible est que les types anonymes ne sont pas publics. Lorsque la méthode renvoie une instance de ce type anonyme, elle renvoie un System.Object qui fait référence à une instance d'un type anonyme - un type dont les informations ne sont pas disponibles pour le programme principal. Le moteur d'exécution dynamique tente de trouver une propriété appelée Personsur l'objet, mais ne peut pas la résoudre à partir des informations de type dont il dispose. En tant que tel, il lève une exception. L'appel à data.Namefonctionne bien car il Persons'agit d'une classe publique, cette information est disponible et peut être facilement résolue.

Cela peut vous affecter dans l'un des cas suivants (sinon plus):

  1. Vous renvoyez un type non public et non interne en utilisant System.Object. 2. Vous retournez un type dérivé non public et non interne via un type de base public et accédez à une propriété du type dérivé qui n'est pas dans le type de base. 3. Vous retournez tout ce qui est enveloppé dans un type anonyme d'un assembly différent.
Robert Važan
la source
1
Pourriez-vous citer votre source dans votre réponse, s'il vous plaît?
d3dave
@ d3dave Les deux affirmations de la réponse peuvent être testées. La visibilité des classes peut être vérifiée dans le décompilateur .NET. Les règles d'accès pour dynamicpeuvent être vérifiées sur une classe de test avec des membres de visibilité variable.
Robert Važan
3
C'est la vraie réponse à la raison pour laquelle ce que faisait OP est un problème.
Matti Virkkunen
1
Je ne peux pas faire fonctionner cela entre un projet source et un projet de test qui sont tous deux netcoreapp1.1. Une idée si c'est juste de ma faute ou si cela ne fonctionne pas dans .NET Core?
Anthony Mastrean
27

Dans mon cas, j'avais un projet de test unitaire que j'avais créé sur Visual Studio et de nombreux cas où j'avais besoin de tester des méthodes sur une bibliothèque de couches de données. Je ne voulais pas tous les changer, j'ai donc marqué l'assemblage de test comme un ami en utilisant:

[assembly:InternalsVisibleTo("MyDataLayerAssemblyName")]

Et cela l'a résolu.

Exemple:

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

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

   [TestClass]
   public class ContactTests
   {
      ...

Références:

Jelgab
la source
1
La raison en est ce qu'a dit Alexander Stepaniuk. Votre commentaire est la solution. Merci!
Pato Loco
Je ne peux pas faire fonctionner cela entre les projets netcoreapp1.1, je ne sais pas si c'est quelque chose que je fais de manière incorrecte.
Anthony Mastrean
Un grand merci Jelgab! Maintenant, je n'ai plus besoin de remplacer dynamic par ExpanoObject! J'utilise l'injection de dépendances dans mes tests unitaires et je n'ai pas pu utiliser Dynamic et le faire fonctionner à partir du projet de test unitaire. Mais cela l'a résolu!
ShameWare
Notez que vous (le développeur) devez l'ajouter dans le projet opposé à partir duquel les types anonymes sont créés, ou les deux, si tel est le cas.
ryanwebjackson
0

Dans mon cas, j'ai un projet de test xUnit.

Où 'content' est une chaîne json .

Ce code génère une erreur:

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

Ce code fonctionne. Utilisez ExpandoObject insted of dynamic comme ceci:

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