dynamic tidak berisi definisi untuk properti dari referensi proyek

93

Saya mendapatkan pesan kesalahan yang mengatakan:

'object' tidak mengandung definisi untuk 'Title'

semua kode juga ada di github

Saya memiliki ConsoleApplication1 yang terlihat seperti ini

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

dan Movie.cs

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

ini berfungsi dengan baik dari proyek yang SAMA, tetapi jika saya menambahkan ConsoleApplication2 dengan referensi ke ConsoleApplication1 dan menambahkan kode yang sama persis

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

Saya mendapatkan kesalahan:

'object' tidak mengandung definisi untuk 'Title' **

meskipun itu dalam objek dinamis.

  • o.Title 'o.Title' melontarkan pengecualian jenis 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' dynamic {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}

Ini tangkapan layarnya: masukkan deskripsi gambar di sini

Saya melakukan sesuatu seperti ini dan mencoba memanggil fungsi film dari proyek uji.

eiu165
sumber

Jawaban:

79

Anda perlu menggunakan ExpandoObject

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

 Console.WriteLine(m.PrintMovie(o));
JamahalSOF
sumber
28
Dia mengalami banyak masalah untuk menulis pertanyaan yang rumit, alangkah baiknya membiarkan dia tahu mengapa dia mendapatkan kesalahan, seperti yang disarankan Robert
Luis Ferrao
2
Sepertinya Anda tidak dapat menggunakan fungsionalitas penginisialisasi inline dengan objek expando?
Roberto Bonini
1
Di mana sebaiknya menggunakan ExpandoObject? untuk membuat objek dinamis atau untuk mengurai objek dinamis?
Hosein Aqajani
Saya harus mencari lebih banyak informasi karena jawaban Robert sangat membantu tetapi saya membutuhkan pemahaman yang lebih dalam. Oreilly memiliki artikel bagus tentang tipe dinamis di sini: oreilly.com/learning/building-c-objects-dynamically
Billy Willoughby
139

Jawaban Jahamal tidak menjelaskan mengapa Anda mendapatkan kesalahan tersebut. Alasannya adalah bahwa kelas anonim internalke majelis. Kata kunci dynamictidak memungkinkan Anda untuk melewati visibilitas anggota.

Solusinya adalah mengganti kelas anonim dengan kelas publik bernama.

Berikut contoh bagus lainnya yang menjelaskan alasan dan kemungkinan solusi lain .

Alasan panggilan ke data2.Persongagal adalah karena jenis informasi data2tidak tersedia saat runtime. Alasan tidak tersedia adalah karena jenis anonim tidak bersifat publik. Ketika metode mengembalikan sebuah instance dari tipe anonim itu, itu mengembalikan sebuah System.Object yang mereferensikan sebuah instance dari tipe anonim - tipe yang infonya tidak tersedia untuk program utama. Runtime dinamis mencoba menemukan properti yang dipanggil Personpada objek, tetapi tidak dapat menyelesaikannya dari jenis informasi yang dimilikinya. Karena itu, ini membuat pengecualian. Panggilan untuk data.Nameberfungsi dengan baik karena Personmerupakan kelas publik, informasi tersebut tersedia dan dapat dengan mudah diselesaikan.

Ini dapat memengaruhi Anda dalam salah satu kasus berikut (jika tidak lebih):

  1. Anda mengembalikan jenis non-publik, non-internal menggunakan System.Object. 2. Anda mengembalikan tipe turunan non-publik dan non-internal melalui tipe basis publik dan mengakses properti dalam tipe turunan yang bukan tipe basis. 3. Anda mengembalikan apa pun yang dibungkus di dalam tipe anonim dari rakitan yang berbeda.
Robert Važan
sumber
1
Bisakah Anda mengutip sumber Anda dalam jawaban Anda?
d3dave
@ d3dave Dua klaim dalam jawaban ini dapat diuji. Visibilitas kelas dapat diperiksa di decompiler .NET. Aturan akses untuk dynamicdapat diperiksa pada kelas tes dengan anggota yang memiliki visibilitas yang berbeda-beda.
Robert Važan
3
Ini adalah jawaban yang sebenarnya mengapa apa yang dilakukan OP menjadi masalah.
Matti Virkkunen
1
Saya tidak bisa mendapatkan ini untuk bekerja antara sumber dan proyek uji yang keduanya netcoreapp1.1. Adakah ide jika itu hanya kesalahan saya atau jika ini tidak berfungsi di .NET Core?
Anthony Mastrean
29

Dalam kasus saya, saya memiliki proyek Unit Test yang saya buat di Visual Studio dan banyak kasus di mana saya perlu menguji metode pada pustaka lapisan data. Saya tidak ingin mengubah semuanya, jadi saya menandai perakitan uji sebagai teman dengan menggunakan:

[assembly:InternalsVisibleTo("MyDataLayerAssemblyName")]

Dan itu menyelesaikannya.

Contoh:

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

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

   [TestClass]
   public class ContactTests
   {
      ...

Referensi:

Jelgab
sumber
1
Alasannya adalah apa yang dikatakan Alexander Stepaniuk. Komentar Anda adalah solusinya. Terima kasih!
Pato Loco
Saya tidak bisa mendapatkan ini berfungsi antara proyek netcoreapp1.1, tidak yakin apakah itu sesuatu yang saya lakukan dengan tidak benar.
Anthony Mastrean
Terima kasih banyak Jelgab! Sekarang saya tidak perlu mengganti dinamika dengan ExpanoObject! Saya menggunakan injeksi ketergantungan dalam pengujian unit saya dan saya tidak dapat menggunakan dinamika dan membuatnya berfungsi dari proyek pengujian unit. Tapi ini menyelesaikannya!
ShameWare
Perhatikan bahwa Anda (pengembang) harus menambahkan ini di proyek yang berlawanan dari mana tipe anonim dibuat, atau keduanya, jika itu masalahnya.
ryanwebjson
0

Dalam kasus saya, saya memiliki proyek uji xUnit.

Di mana 'konten' adalah string json .

Kode ini melempar kesalahan:

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

Kode ini berfungsi. Gunakan ExpandoObject insted dinamis seperti ini:

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