Dynamic nie zawiera definicji właściwości z odniesienia do projektu

93

Otrzymuję komunikat o błędzie:

„obiekt” nie zawiera definicji „tytułu”

cały kod jest również włączony githubie

Mam ConsoleApplication1, która wygląda tak

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

i Movie.cs

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

działa dobrze z projektu SAME, ale jeśli dodam ConsoleApplication2 z odwołaniem do ConsoleApplication1 i dodam dokładnie ten sam kod

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

Pojawia się błąd:

„obiekt” nie zawiera definicji „tytułu” **

mimo że znajduje się w obiekcie dynamicznym.

  • o.Title „o.Title” zgłosił wyjątek typu „Microsoft.CSharp.RuntimeBinder.RuntimeBinderException” dynamiczny {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}

Oto zrzut ekranu: wprowadź opis obrazu tutaj

Robię coś takiego i próbuję wywołać funkcję filmu z projektu testowego.

eiu165
źródło
3
możliwy duplikat „dynamicznego”
Jesse C. Slicer

Odpowiedzi:

79

Musisz użyć ExpandoObject

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

 Console.WriteLine(m.PrintMovie(o));
JamahalSOF
źródło
28
Zadał sobie wiele trudu, aby napisać skomplikowane pytanie, byłoby miło dać mu znać, dlaczego dostaje błąd, jak sugeruje Robert
Luis Ferrao
2
Nie wygląda na to, że możesz użyć funkcji inicjalizatora inline z obiektem expando?
Roberto Bonini
1
Gdzie należy używać ExpandoObject? do tworzenia dynamicznego obiektu czy do analizowania dynamicznego obiektu?
Hosein Aqajani,
Musiałem poszukać więcej informacji, ponieważ odpowiedź Roberta była pomocna, ale potrzebowałem głębszego zrozumienia. Oreilly miał dobry artykuł o typach dynamicznych tutaj: oreilly.com/learning/building-c-objects-dynamically
Billy Willoughby
139

Odpowiedź Jahamala nie mówi, dlaczego otrzymujesz błąd. Powodem jest to, że klasa anonimowa jest przypisana internaldo zestawu. Słowo kluczowe dynamicnie pozwala na ominięcie widoczności członków.

Rozwiązaniem jest zastąpienie anonimowej klasy nazwaną klasą publiczną.

Oto kolejny dobry przykład wyjaśniający przyczynę i inne możliwe rozwiązanie .

Przyczyną data2.Personniepowodzenia wywołania jest to, że informacje o typie data2nie są dostępne w czasie wykonywania. Nie jest dostępny, ponieważ typy anonimowe nie są publiczne. Kiedy metoda zwraca wystąpienie tego typu anonimowego, zwraca System.Object, który odwołuje się do wystąpienia typu anonimowego - typu, którego informacje nie są dostępne dla programu głównego. Dynamiczne środowisko wykonawcze próbuje znaleźć właściwość wywoływaną Personw obiekcie, ale nie może jej rozwiązać na podstawie posiadanych informacji o typie. W związku z tym zgłasza wyjątek. To wezwanie data.Namedziała dobrze, ponieważ Personjest to klasa publiczna, informacje te są dostępne i można je łatwo rozwiązać.

Może to wpłynąć na Ciebie w każdym z następujących przypadków (jeśli nie więcej):

  1. Zwracasz niepubliczny, nie wewnętrzny typ przy użyciu System.Object. 2. Zwracasz niepubliczny, nie-wewnętrzny typ pochodny za pośrednictwem publicznego typu podstawowego i uzyskujesz dostęp do właściwości w typie pochodnym, którego nie ma w typie podstawowym. 3. Zwracasz wszystko, co jest opakowane w anonimowy typ z innego zestawu.
Robert Važan
źródło
1
Czy mógłbyś podać swoje źródło w swojej odpowiedzi?
d3dave
@ d3dave Można przetestować dwa twierdzenia w odpowiedzi. Widoczność klas można sprawdzić w dekompilatorze .NET. Reguły dostępu dynamicmożna sprawdzić w klasie testowej z członkami o różnej widoczności.
Robert Važan
3
To jest prawdziwa odpowiedź na pytanie, dlaczego to, co robił OP, jest problemem.
Matti Virkkunen
1
Nie mogę sprawić, aby to działało między projektem źródłowym i testowym, które są jednocześnie aplikacjami netcoreapp1.1. Masz jakiś pomysł, czy to tylko moja wina, czy to nie działa w .NET Core?
Anthony Mastrean
29

W moim przypadku miałem projekt testów jednostkowych, który stworzyłem w Visual Studio i wiele przypadków, w których musiałem przetestować metody w bibliotece warstwy danych. Nie chciałem zmieniać ich wszystkich, więc oznaczyłem montaż testowy jako przyjaciel, używając:

[assembly:InternalsVisibleTo("MyDataLayerAssemblyName")]

I to rozwiązało problem.

Przykład:

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

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

   [TestClass]
   public class ContactTests
   {
      ...

Bibliografia:

Jelgab
źródło
1
Powodem jest to, co powiedział Aleksander Stepaniuk. Twój komentarz jest rozwiązaniem. Dzięki!
Pato Loco
Nie mogę sprawić, by to działało między projektami netcoreapp1.1, nie jestem pewien, czy jest to coś, co robię nieprawidłowo.
Anthony Mastrean
Wielkie dzięki Jelgab! Teraz nie muszę zastępować dynamiki ExpanoObject! Używam wstrzykiwania zależności w moich testach jednostkowych i nie mogłem użyć dynamiki i sprawić, by działał z projektu testu jednostkowego. Ale to rozwiązało problem!
ShameWare
Zauważ, że ty (programista) musisz dodać to w przeciwnym projekcie, z którego są tworzone typy anonimowe, lub w obu, jeśli tak jest.
ryanwebjackson
0

W moim przypadku mam projekt testowy xUnit.

Gdzie „content” to ciąg json .

Ten kod zgłasza błąd:

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

Ten kod działa. Użyj ExpandoObject zamiast dynamiki w następujący sposób:

dynamic parsed = JsonConvert.DeserializeObject<ExpandoObject>(content);
Guilherme Ferreira
źródło