Pertanyaan Tidak Dapat Melakukan Transmisi dari Kelas Orangtua ke Kelas Anak


Saya mencoba mentransmisi dari kelas induk ke kelas turunan, tetapi saya mendapatkan InvalidCastException. Kelas anak hanya memiliki satu properti bertipe int. Apakah ada yang tahu apa yang harus saya lakukan?


75
2018-06-12 19:39


asal


Jawaban:


Anda tidak bisa melempar mamalia ke anjing - mungkin kucing.

Anda tidak bisa memasukkan makanan ke dalam sandwich - mungkin itu cheeseburger.

Anda tidak dapat mentransmisikan mobil ke Ferrari - mungkin Honda, atau lebih spesifik lagi, Anda tidak dapat mentransmisikan Ferrari 360 Modena ke Ferrari 360 Challange Stradale - ada bagian-bagian differnt, meskipun keduanya Ferrari 360s.


97
2018-05-12 15:44



Cara sederhana untuk melakukan downcast di C # adalah dengan serialisasi induk dan kemudian deserialize ke anak.

 var serializedParent = JsonConvert.SerializeObject(parentInstance); 
 Child c  = JsonConvert.DeserializeObject<Child>(serializedParent);

Saya memiliki aplikasi konsol sederhana yang memasukkan hewan ke dalam anjing, menggunakan dua baris kode di atas sini


87
2017-12-21 23:10



Instance yang merujuk referensi kelas dasar Anda bukan merupakan instance dari kelas anak Anda. Tidak ada yang salah.

Lebih spesifik:

Base derivedInstance = new Derived();
Base baseInstance = new Base();

Derived good = (Derived)derivedInstance; // OK
Derived fail = (Derived)baseInstance; // Throws InvalidCastException

Agar pemain menjadi sukses, contoh yang Anda tolak harus berupa turunan kelas yang Anda tolak (atau setidaknya, kelas yang Anda suruh harus berada dalam hirarki kelas instance), jika tidak, pemain akan gagal.


53
2018-06-12 19:40



Ada beberapa kasus ketika pemain seperti itu masuk akal.
Saya kasus saya, saya menerima kelas BASE melalui jaringan, dan saya membutuhkan lebih banyak fitur untuk itu. Jadi menurunkannya untuk menanganinya di sisi saya dengan semua lonceng dan peluit yang saya inginkan, dan mentransmisikan kelas BASE yang diterima ke DERIVED bukan pilihan (Melempar InvalidCastException of Course)

Satu praktis berpikir-out-of-the-box SOLUSI adalah untuk menyatakan kelas Pembantu EXTENSION yang TIDAK mewarisi kelas BASE sebenarnya, tetapi TERMASUK TI sebagai anggota.

public class BaseExtension
{
   Base baseInstance;

   public FakeDerived(Base b)
   {
      baseInstance = b;
   }

   //Helper methods and extensions to Base class added here
}

Jika Anda memiliki kopling longgar dan hanya perlu beberapa fitur tambahan untuk kelas dasar tanpa SANGAT memiliki kebutuhan absolut derivasi, itu bisa menjadi solusi cepat dan sederhana.


14
2017-10-27 15:30



Itu akan melanggar prinsip berorientasi objek. Saya akan mengatakan solusi elegan di sini dan di tempat lain dalam proyek ini menggunakan kerangka pemetaan objek seperti AutoMapper untuk mengkonfigurasi proyeksi.

Berikut adalah konfigurasi yang sedikit lebih kompleks daripada yang diperlukan tetapi cukup fleksibel untuk sebagian besar kasus:

public class BaseToChildMappingProfile : Profile
{
    public override string ProfileName
    {
        get { return "BaseToChildMappingProfile"; }
    }

    protected override void Configure()
    {
        Mapper.CreateMap<BaseClass, ChildClassOne>();
        Mapper.CreateMap<BaseClass, ChildClassTwo>();
    }
}


public class AutoMapperConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(x =>
        {
            x.AddProfile<BaseToChildMappingProfile>();
        });
    }
}

Saat aplikasi mulai dihubungi AutoMapperConfiguration.Configure() dan kemudian Anda dapat memproyeksikan seperti ini:

ChildClassOne child = Mapper.Map<BaseClass, ChildClassOne>(baseClass);

Properti dipetakan berdasarkan konvensi sehingga jika kelas diwarisi nama properti persis sama dan pemetaan dikonfigurasi secara otomatis. Anda dapat menambahkan properti tambahan dengan mengutak-atik konfigurasi. Lihat dokumentasi .


13
2018-04-01 23:47



Paul, Anda tidak bertanya 'Bisakah saya melakukannya' - saya berasumsi Anda ingin tahu bagaimana untuk melakukannya!

Kami harus melakukan ini pada proyek - ada banyak kelas yang kami atur secara umum hanya sekali, kemudian menginisialisasi properti khusus untuk kelas turunan. Saya menggunakan VB jadi sampel saya ada di VB (sulit noogies), tapi saya mencuri sampel VB dari situs ini yang juga memiliki versi C # yang lebih baik:

http://www.eggheadcafe.com/tutorials/aspnet/a4264125-fcb0-4757-9d78-ff541dfbcb56/net-reflection--copy-cl.aspx

Kode sampel:

Imports System
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Text
Imports System.Diagnostics

Module ClassUtils

    Public Sub CopyProperties(ByVal dst As Object, ByVal src As Object)
        Dim srcProperties() As PropertyInfo = src.GetType.GetProperties
        Dim dstType = dst.GetType

        If srcProperties Is Nothing Or dstType.GetProperties Is Nothing Then
            Return
        End If

        For Each srcProperty As PropertyInfo In srcProperties
            Dim dstProperty As PropertyInfo = dstType.GetProperty(srcProperty.Name)

            If dstProperty IsNot Nothing Then
                If dstProperty.PropertyType.IsAssignableFrom(srcProperty.PropertyType) = True Then
                    dstProperty.SetValue(dst, srcProperty.GetValue(src, Nothing), Nothing)
                End If
            End If
        Next
    End Sub
End Module


Module Module1
    Class base_class
        Dim _bval As Integer
        Public Property bval() As Integer
            Get
                Return _bval
            End Get
            Set(ByVal value As Integer)
                _bval = value
            End Set
        End Property
    End Class
    Class derived_class
        Inherits base_class
        Public _dval As Integer
        Public Property dval() As Integer
            Get
                Return _dval
            End Get
            Set(ByVal value As Integer)
                _dval = value
            End Set
        End Property
    End Class
    Sub Main()
        ' NARROWING CONVERSION TEST
        Dim b As New base_class
        b.bval = 10
        Dim d As derived_class
        'd = CType(b, derived_class) ' invalidcast exception 
        'd = DirectCast(b, derived_class) ' invalidcast exception
        'd = TryCast(b, derived_class) ' returns 'nothing' for c
        d = New derived_class
        CopyProperties(d, b)
        d.dval = 20
        Console.WriteLine(b.bval)
        Console.WriteLine(d.bval)
        Console.WriteLine(d.dval)
        Console.ReadLine()
    End Sub
End Module

Tentu saja ini tidak benar-benar casting. Ini membuat objek turunan baru dan menyalin properti dari induknya, meninggalkan properti anak kosong. Itu saja yang perlu saya lakukan dan sepertinya semua yang perlu Anda lakukan. Catatan itu hanya menyalin properti, bukan anggota (variabel publik) di kelas (tetapi Anda dapat memperpanjangnya untuk melakukan itu jika Anda malu mengungkapkan anggota publik).

Casting secara umum menciptakan 2 variabel yang menunjuk ke objek yang sama (tutorial mini di sini, jangan membuang pengecualian kasus sudut pada saya). Ada konsekuensi penting untuk ini (latihan untuk pembaca)!

Tentu saja saya harus mengatakan mengapa languague tidak membiarkan Anda pergi dari basis ke menurunkan turunan, tetapi melakukan cara lain. bayangkan sebuah kasus di mana Anda dapat mengambil contoh dari kotak teks winforms (diturunkan) dan menyimpannya dalam variabel tipe kontrol Winforms. Tentu saja 'kontrol' dapat memindahkan objek di sekitar OK dan Anda dapat menangani semua hal 'kontrol-y' tentang kotak teks (misalnya, atas, kiri, .teks properti). Item khusus textbox (mis., .Multiline) tidak dapat dilihat tanpa mentransmisikan variabel tipe 'kontrol' yang menunjuk ke kotak teks di memori, tetapi masih ada di memori.

Sekarang bayangkan, Anda memiliki kontrol, dan Anda ingin mengaitkan variabel jenis textbox ke sana. Kontrol dalam memori hilang 'multiline' dan hal-hal textboxy lainnya. Jika Anda mencoba mereferensikannya, kontrol tidak akan secara ajaib menumbuhkan properti multiline! Properti (lihatlah seperti variabel anggota di sini, yang sebenarnya menyimpan nilai - karena ada di dalam memori instance kotak teks) harus ada. Karena Anda casting, ingat, itu harus menjadi objek yang sama yang Anda tunjuk. Oleh karena itu itu bukan pembatasan bahasa, secara filosofis tidak mungkin untuk kasus dengan cara seperti itu.


9
2018-05-12 15:40



Saya telah melihat sebagian besar orang berkata casting orang tua ke anak eksplisit tidak mungkin, itu sebenarnya tidak benar. Mari kita mulai revisi dan coba buktikan dengan contoh.

Seperti yang kita ketahui di .net semua casting memiliki dua kategori besar.

  1. Untuk tipe Nilai
  2. Untuk tipe Referensi (dalam kasus Anda jenis referensi)

Tipe referensi memiliki lebih lanjut tiga kasus situasi utama di mana skenario apa pun bisa berbohong.

Child to Parent (Pengecatan implisit - Selalu berhasil)

Kasus 1. Anak ke orang tua langsung atau tidak langsung

Employee e = new Employee();
Person p = (Person)e; //Allowed

Induk ke Anak (Pengecekan eksplisit - Dapat berhasil)

Kasus 2. Variabel induk memegang objek induk (Tidak diizinkan)

Person p = new Person();  // p is true Person object
Employee e = (Employee)p; //Runtime err : InvalidCastException <-------- Yours issue

Kasus 3. Variabel induk memegang objek anak (Selalu Berhasil)

Catatan: Karena objek memiliki sifat polimorfik, adalah mungkin untuk variabel tipe kelas induk untuk menahan jenis anak.

Person p = new Employee(); // p actually is Employee
Employee e = (Employee)p; // Casting allowed

Kesimpulan: Setelah membaca di atas semua, semoga ini akan masuk akal sekarang seperti bagaimana konversi orang tua menjadi anak dimungkinkan (Kasus 3).

Jawab pertanyaan :

Jawaban Anda adalah   di kasus 2Di mana Anda dapat melihat pengecoran tersebut tidak diizinkan oleh OOP dan Anda mencoba untuk melanggar salah satu aturan dasar OOP. Jadi selalu pilih jalur aman.

Lebih jauh lagi, untuk menghindari situasi yang luar biasa seperti itu .net telah merekomendasikan penggunaan adalah sebagai operator yang akan membantu Anda untuk mengambil keputusan dan memberikan casting yang aman.


5
2017-10-17 14:56