dynamic не содержит определения свойства из ссылки на проект


93

Я получаю сообщение об ошибке:

'объект' не содержит определения для 'Заголовка'

весь код тоже на 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));
        }
    }
}

Я получаю сообщение об ошибке:

'объект' не содержит определения для 'Заголовка' **

даже если он находится в динамическом объекте.

  • o.Title 'o.Title' вызвало исключение типа 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' dynamic {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}

Вот скриншот: введите описание изображения здесь

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


Ответы:


79

Вам нужно использовать ExpandoObject

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

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

28
У него было много проблем, чтобы написать сложный вопрос, было бы неплохо сообщить ему, почему он получает ошибку, как предлагает Роберт
— Луис Феррао

2
Не кажется, что вы можете использовать функциональность встроенного инициализатора с объектом expando?
— Роберто Бонини

1
Где использовать ExpandoObject? для создания динамического объекта или для анализа динамического объекта?
— Хосейн Акаджани

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

139

В ответе Джахамаля не говорится, почему вы получаете ошибку. Причина в том, что анонимный класс относится internalк сборке. Ключевое слово dynamicне позволяет вам обойти видимость участников.

Решение состоит в том, чтобы заменить анонимный класс именованным публичным классом.

Вот еще один хороший пример, объясняющий причину и другое возможное решение .

Причина data2.Personсбоя вызова в том, что информация о типе data2недоступна во время выполнения. Причина, по которой он недоступен, заключается в том, что анонимные типы не являются общедоступными. Когда метод возвращает экземпляр этого анонимного типа, он возвращает System.Object, который ссылается на экземпляр анонимного типа - типа, информация о котором недоступна для основной программы. Среда динамического выполнения пытается найти свойство, вызываемое Personу объекта, но не может разрешить его на основе имеющейся у него информации о типе. Таким образом, он вызывает исключение. Вызов to data.Nameработает нормально, поскольку Personэто открытый класс, эта информация доступна и может быть легко решена.

Это может повлиять на вас в любом из следующих случаев (если не больше):

  1. Вы возвращаете закрытый, не внутренний тип, используя System.Object. 2. Вы возвращаете закрытый, не внутренний производный тип через общедоступный базовый тип и получаете доступ к свойству в производном типе, которого нет в базовом типе. 3. Вы возвращаете все, что заключено в анонимный тип, из другой сборки.

1
Не могли бы вы указать свой источник в своем ответе?
— d3dave

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

3
Это настоящий ответ на вопрос, почему то, что делал OP, является проблемой.
— Матти Вирккунен

1
Я не могу заставить это работать между исходным и тестовым проектами, которые оба являются netcoreapp1.1. Есть идеи, это только моя вина или это не работает в .NET Core?
— Энтони Мастрян

29

В моем случае у меня был проект модульного теста, который я создал в 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
Причина в том, что сказал Александр Степанюк. Ваш комментарий - это решение. Благодарность!
— Pato Loco

Я не могу заставить это работать между проектами netcoreapp1.1, не уверен, что я что-то делаю неправильно.
— Энтони Мастрян

Огромное спасибо, Джелгаб! Теперь мне не нужно заменять динамический на ExpanoObject! Я использую внедрение зависимостей в своих модульных тестах, и мне не удалось использовать динамический и заставить его работать из проекта модульного теста. Но это решило ее!
— ShameWare

Обратите внимание, что вы (разработчик) должны добавить это в противоположный проект, из которого создаются анонимные типы, или в оба, если это так.
— ryanwebjackson

0

В моем случае у меня есть тестовый проект xUnit.

Где «контент» - это строка в формате json .

Этот код выдает ошибку:

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

Этот код работает. Используйте ExpandoObject вместо dynamic следующим образом:

dynamic parsed = JsonConvert.DeserializeObject<ExpandoObject>(content);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.