Dynamic не містить визначення властивості з посилання на проект


93

Я отримую повідомлення про помилку:

'object' не містить визначення для 'Title'

весь код також на github

У мене є ConsoleApplication1, яка виглядає так

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

та Movie.cs

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

він чудово працює з того самого проекту, але якщо я додаю ConsoleApplication2 з посиланням на ConsoleApplication1 і додаю Точний той самий код

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

Я отримую повідомлення про помилку:

'object' не містить визначення для 'Title' **

навіть якщо він знаходиться в динамічному об'єкті.

  • o.Title 'o.Title' видав виняток типу 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' динамічний {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}

Ось знімок екрану: введіть тут опис зображення

Я роблю щось подібне і намагаюся викликати функцію фільму з тестового проекту.


Відповіді:


79

Вам потрібно використовувати ExpandoObject

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

 Console.WriteLine(m.PrintMovie(o));

28
Він зіткнувся з багатьма проблемами,
написавши складне

2
Не здається, що ви можете використовувати функцію вбудованого ініціалізатора з об’єктом extendo?
Роберто Боніні

1
Де слід використовувати ExpandoObject? для створення динамічного об'єкта або для синтаксичного аналізу динамічного об'єкта?
Hosein Aqajani

Мені довелося шукати більше інформації, оскільки відповідь Роберта була корисною, але мені потрібно було глибше зрозуміти. Тут у Орейлі була хороша стаття про динамічні типи: oreilly.com/learning/building-c-objects-dynamically
Біллі Віллоубі,

139

У відповіді Джахамала не сказано, чому ви отримуєте помилку. Причина в тому, що анонімний клас призначений internalдля збірки. Ключове dynamicслово не дозволяє вам обійти видимість учасників.

Рішення полягає в тому, щоб замінити анонімний клас на іменований публічний клас.

Ось ще один хороший приклад, що пояснює причину та інше можливе рішення .

Причиною data2.Personпомилки виклику є те, що інформація про тип data2недоступна під час виконання. Причина, по якій він недоступний, полягає в тому, що анонімні типи не є загальнодоступними. Коли метод повертає екземпляр цього анонімного типу, він повертає System.Object, яке посилається на екземпляр анонімного типу - типу, інформація якого недоступна для основної програми. Динамічний час виконання намагається знайти властивість, що викликається Personдля об'єкта, але не може вирішити це з інформації про тип, яку він має. Як такий, він створює виняток. Заклик до data.Nameвідмінно працює, оскільки Personє загальнодоступним класом, ця інформація доступна і може бути легко вирішена.

Це може вплинути на вас у будь-якому з наступних випадків (якщо не більше):

  1. Ви повертаєте непублічний, не внутрішній тип використання System.Object. 2. Ви повертаєте непублічний, не внутрішній похідний тип через загальнодоступний базовий тип і отримуєте доступ до властивості у похідному типі, яке не є базовим типом. 3. Ви повертаєте будь-що, загорнуте в анонімний тип, з іншої збірки.

1
Чи не могли б Ви навести своє джерело у своїй відповіді, будь ласка?
d3dave

@ d3dave Два твердження у відповіді можна перевірити. Видимість класу можна перевірити в декомпіляторі .NET. Правила доступу для dynamicможна перевірити на тестовому класі з учасниками різної видимості.
Роберт Важан,

3
Це справжня відповідь на те, чому те, що робив ОП, є проблемою.
Матті Вірккунен

1
Я не можу змусити це працювати між джерелом та тестовим проектом, які одночасно є netcoreapp1.1. Будь-яка ідея, чи це лише моя вина, чи це не працює в .NET Core?
Ентоні Мастреан

29

У моєму випадку у мене був проект Unit Test, який я створив у Visual Studio, і багато випадків, коли мені потрібно було протестувати методи в бібліотеці рівня даних. Я не хотів змінювати їх усіх, тому позначив тестову збірку як друга, використовуючи:

[assembly:InternalsVisibleTo("MyDataLayerAssemblyName")]

І це вирішило.

Приклад:

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

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

   [TestClass]
   public class ContactTests
   {
      ...

Список літератури:


1
Причина в тому, що сказав Олександр Степанюк. Ваш коментар - це рішення. Дякую!
Пато Локо

Я не можу змусити це працювати між проектами netcoreapp1.1, не впевнений, що це щось я роблю неправильно.
Ентоні Мастреан,

Величезне спасибі Єлгаба! Тепер мені не потрібно замінювати динамічний на ExpanoObject! Я використовую ін’єкцію залежностей у своїх модульних тестах, і я не зміг використовувати динамічну систему, щоб вона працювала за проектом модульної перевірки. Але це вирішило!
ShameWare

Зверніть увагу, що ви (розробник) повинні додати це у протилежному проекті, з якого створюються анонімні типи, або в обох випадках, якщо це так.
ryanwebjackson

0

У моєму випадку у мене є проект тесту xUnit.

Де 'вміст' - це рядок json .

Цей код видає помилку:

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

Цей код працює. Використовуйте ExpandoObject, вкладений у динаміку, як це:

dynamic parsed = JsonConvert.DeserializeObject<ExpandoObject>(content);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.