dynamic enthält keine Definition für eine Eigenschaft aus einer Projektreferenz

91

Ich erhalte eine Fehlermeldung, die besagt:

'Objekt' enthält keine Definition für 'Titel'

Der gesamte Code ist auch auf Github

Ich habe eine ConsoleApplication1, die so aussieht

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

und Movie.cs

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

Es funktioniert gut aus dem gleichen Projekt, aber wenn ich ConsoleApplication2 mit einem Verweis auf ConsoleApplication1 hinzufüge und den exakt gleichen Code hinzufüge

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

Ich erhalte eine Fehlermeldung:

'Objekt' enthält keine Definition für 'Titel' **

obwohl es im dynamischen Objekt ist.

  • o.Title 'o.Title' hat eine Ausnahme vom Typ 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' ausgelöst. dynamic {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}

Hier ist ein Screenshot: Geben Sie hier die Bildbeschreibung ein

Ich mache so etwas und versuche, die Filmfunktion aus einem Testprojekt aufzurufen.

eiu165
quelle

Antworten:

80

Sie müssen ein ExpandoObject verwenden

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

 Console.WriteLine(m.PrintMovie(o));
JamahalSOF
quelle
28
Er hatte große Mühe, eine ausführliche Frage zu schreiben. Es wäre schön, ihn wissen zu lassen, warum er den Fehler bekommt, wie Robert vorschlägt
Luis Ferrao
2
Scheint nicht, dass Sie die Inline-Initialisierungsfunktion mit expando object verwenden können?
Roberto Bonini
1
Wo soll ExpandoObject verwendet werden? zum Erstellen eines dynamischen Objekts oder zum Parsen eines dynamischen Objekts?
Hosein Aqajani
Ich musste nach weiteren Informationen suchen, da Roberts Antwort hilfreich war, aber ich brauchte ein tieferes Verständnis. Oreilly hatte hier einen guten Artikel über dynamische Typen: oreilly.com/learning/building-c-objects-dynamically
Billy Willoughby
136

Jahamals Antwort sagt nicht, warum Sie den Fehler erhalten. Der Grund ist, dass die anonyme Klasse internalzur Assembly gehört. Mit dem Schlüsselwort dynamickönnen Sie die Sichtbarkeit von Mitgliedern nicht umgehen.

Die Lösung besteht darin, die anonyme Klasse durch eine benannte öffentliche Klasse zu ersetzen.

Hier ist ein weiteres gutes Beispiel, das den Grund und eine andere mögliche Lösung erklärt .

Der Grund, warum der Aufruf data2.Personfehlschlägt, ist, dass die Typinformationen von data2zur Laufzeit nicht verfügbar sind. Der Grund, warum es nicht verfügbar ist, ist, dass anonyme Typen nicht öffentlich sind. Wenn die Methode eine Instanz dieses anonymen Typs zurückgibt, gibt sie ein System.Object zurück, das auf eine Instanz eines anonymen Typs verweist - einen Typ, dessen Informationen dem Hauptprogramm nicht zur Verfügung stehen. Die dynamische Laufzeit versucht, eine Personfür das Objekt aufgerufene Eigenschaft zu finden , kann sie jedoch nicht anhand der Typinformationen auflösen. Als solches löst es eine Ausnahme aus. Der Aufruf zum Funktionieren data.Namefunktioniert einwandfrei, da Persones sich um eine öffentliche Klasse handelt, deren Informationen verfügbar sind und leicht aufgelöst werden können.

Dies kann Sie in einem der folgenden Fälle betreffen (wenn nicht mehr):

  1. Sie geben einen nicht öffentlichen, nicht internen Typ mit zurück System.Object. 2. Sie geben einen nicht öffentlichen, nicht internen abgeleiteten Typ über einen öffentlichen Basistyp zurück und greifen auf eine Eigenschaft im abgeleiteten Typ zu, die nicht im Basistyp enthalten ist. 3. Sie geben alles zurück, was in einem anonymen Typ von einer anderen Assembly verpackt ist.
Robert Važan
quelle
1
Könnten Sie bitte Ihre Quelle in Ihrer Antwort angeben?
d3dave
@ d3dave Die beiden Ansprüche in der Antwort können getestet werden. Die Sichtbarkeit von Klassen kann im .NET-Dekompiler überprüft werden. Zugriffsregeln für dynamickönnen in einer Testklasse mit Mitgliedern unterschiedlicher Sichtbarkeit überprüft werden.
Robert Važan
3
Dies ist die eigentliche Antwort darauf, warum das, was OP tat, ein Problem ist.
Matti Virkkunen
1
Ich kann dies nicht zwischen einer Quelle und einem Testprojekt zum Laufen bringen, die beide netcoreapp1.1 sind. Irgendeine Idee, ob es nur meine Schuld ist oder ob dies in .NET Core nicht funktioniert?
Anthony Mastrean
26

In meinem Fall hatte ich ein Unit-Test-Projekt, das ich in Visual Studio erstellt habe, und viele Fälle, in denen ich Methoden in einer Datenschichtbibliothek testen musste. Ich wollte nicht alle ändern, also habe ich die Testbaugruppe als Freund markiert, indem ich Folgendes verwendet habe:

[assembly:InternalsVisibleTo("MyDataLayerAssemblyName")]

Und das hat es gelöst.

Beispiel:

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

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

   [TestClass]
   public class ContactTests
   {
      ...

Verweise:

Jelgab
quelle
1
Der Grund ist, was Alexander Stepaniuk sagte. Ihr Kommentar ist die Lösung. Vielen Dank!
Pato Loco
Ich kann dies nicht zwischen netcoreapp1.1-Projekten zum Laufen bringen, bin mir nicht sicher, ob es etwas ist, was ich falsch mache.
Anthony Mastrean
Vielen Dank Jelgab! Jetzt muss ich Dynamic nicht mehr durch ExpanoObject ersetzen! Ich verwende die Abhängigkeitsinjektion in meinen Komponententests und konnte Dynamic nicht verwenden und habe es aus dem Komponententestprojekt heraus funktionieren lassen. Aber das hat es gelöst!
ShameWare
Beachten Sie, dass Sie (der Entwickler) dies im gegenüberliegenden Projekt hinzufügen müssen, aus dem die anonymen Typen erstellt werden, oder in beiden Fällen, wenn dies der Fall ist.
Ryanwebjackson
0

In meinem Fall habe ich ein xUnit-Testprojekt.

Wobei 'Inhalt' eine JSON-Zeichenfolge ist .

Dieser Code löst einen Fehler aus:

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

Dieser Code funktioniert. Verwenden Sie ExpandoObject wie folgt:

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