Apakah mungkin untuk menetapkan objek kelas dasar ke referensi kelas turunan dengan typecast eksplisit?


89

Apakah mungkin untuk menetapkan objek kelas dasar ke referensi kelas turunan dengan typecast eksplisit di C # ?.

Saya telah mencobanya dan itu menciptakan kesalahan waktu berjalan.

Jawaban:


100

Tidak. Referensi ke kelas turunan harus benar-benar merujuk ke turunan kelas turunan (atau null). Jika tidak, bagaimana Anda mengharapkannya berperilaku?

Sebagai contoh:

object o = new object();
string s = (string) o;
int i = s.Length; // What can this sensibly do?

Jika Anda ingin dapat mengonversi instance dari tipe dasar ke tipe turunan, saya sarankan Anda menulis metode untuk membuat turunan tipe yang sesuai. Atau lihat pohon warisan Anda lagi dan coba desain ulang sehingga Anda tidak perlu melakukan ini sejak awal.


72
@ Mike: Kode dikompilasi dengan baik. Itu jatuh pada waktu eksekusi :)
Jon Skeet

1
Lalu apa yang sebenarnya terjadi ketika kita menulis Base b = new Derived (); ? Akankah itu membuat objek untuk kelas dasar dan turunan?
Ashif Nataliya

3
@Akie: Tidak, ini membuat satu tipe objek Derived, tetapi Anda dapat memperlakukan Derivedreferensi sebagai Basereferensi.
Jon Skeet

Jadi, apakah ada perbedaan hasil objek untuk kedua pernyataan ini? Basis b = Basis baru () dan Basis b = Derivasi baru ()? apa keuntungan menggunakan salah satunya?
Ashif Nataliya

4
@ Akie: Ya, satu membuat instance Base, dan yang lain membuat instance Derived. Jika Anda memanggil metode virtual byang telah diganti Derived, Anda akan melihat Derivedperilakunya jika Anda memiliki instance Derived. Tetapi tidak tepat untuk membahas detail di utas komentar Stack Overflow - Anda harus benar-benar membaca buku C # atau tutorial yang bagus, karena ini adalah hal yang cukup mendasar.
Jon Skeet

47

Tidak, itu tidak mungkin karena menugaskannya ke referensi kelas turunan akan seperti mengatakan "Kelas dasar adalah pengganti yang mampu sepenuhnya untuk kelas turunan, ia dapat melakukan semua yang dapat dilakukan kelas turunan", yang tidak benar karena kelas turunan dalam penawaran umum lebih banyak fungsionalitas daripada kelas dasarnya (setidaknya, itulah ide di balik warisan).

Anda bisa menulis konstruktor di kelas turunan mengambil objek kelas dasar sebagai parameter, menyalin nilai.

Sesuatu seperti ini:

public class Base {
    public int Data;

    public void DoStuff() {
        // Do stuff with data
    }
}

public class Derived : Base {
    public int OtherData;

    public Derived(Base b) {
        this.Data = b.Data;
        OtherData = 0; // default value
    }

    public void DoOtherStuff() {
        // Do some other stuff
    }
}

Dalam hal ini Anda akan menyalin objek dasar dan mendapatkan objek kelas turunan yang berfungsi penuh dengan nilai default untuk anggota turunan. Dengan cara ini Anda juga dapat menghindari masalah yang ditunjukkan oleh Jon Skeet:

Base b = new Base();//base class
Derived d = new Derived();//derived class

b.DoStuff();    // OK
d.DoStuff();    // Also OK
b.DoOtherStuff();    // Won't work!
d.DoOtherStuff();    // OK

d = new Derived(b);  // Copy construct a Derived with values of b
d.DoOtherStuff();    // Now works!

23

Saya punya masalah ini dan menyelesaikannya dengan menambahkan metode yang mengambil parameter tipe dan mengubah objek saat ini menjadi tipe itu.

public TA As<TA>() where TA : Base
{
    var type = typeof (TA);
    var instance = Activator.CreateInstance(type);

     PropertyInfo[] properties = type.GetProperties();
     foreach (var property in properties)
     {
         property.SetValue(instance, property.GetValue(this, null), null);
     }

     return (TA)instance;
}

Itu berarti Anda dapat menggunakannya dalam kode Anda seperti ini:

var base = new Base();
base.Data = 1;
var derived = base.As<Derived>();
Console.Write(derived.Data); // Would output 1

Anda harus menggunakan tipe kelas saat ini (kelas dasar) untuk mendapatkan dan menyetel properti karena itu adalah nilai yang ingin Anda petakan ke kelas turunan.
Bowofola

1
Jika Anda memiliki properti yang tidak dapat ditulis dalam tipe turunan, Anda mungkin harus mengubah ke: if (property.CanWrite) property.SetValue (instance, property.GetValue (this, null), null);
pengguna3478586

10

Seperti yang telah dijawab banyak orang, Tidak.

Saya menggunakan kode berikut pada kesempatan yang tidak menguntungkan ketika saya perlu menggunakan tipe dasar sebagai tipe turunan. Ya, itu adalah pelanggaran Prinsip Substitusi Liskov (LSP) dan ya, sebagian besar waktu kami lebih menyukai komposisi daripada warisan. Alat peraga untuk Markus Knappen Johansson yang jawaban aslinya didasarkan pada ini.

Kode ini di kelas dasar:

    public T As<T>()
    {
        var type = typeof(T);
        var instance = Activator.CreateInstance(type);

        if (type.BaseType != null)
        {
            var properties = type.BaseType.GetProperties();
            foreach (var property in properties)
                if (property.CanWrite)
                    property.SetValue(instance, property.GetValue(this, null), null);
        }

        return (T) instance;
    }

Memungkinkan:

    derivedObject = baseObect.As<derivedType>()

Karena menggunakan refleksi, maka "mahal". Gunakan sesuai.


Saya baru saja mencoba ini, dan membayangkan, ini dapat ditingkatkan lebih jauh, dengan membebani operator eksplisit (dan juga operator implisit) .. tetapi - Kompilator tidak mengizinkannya: user-defined conversions to or from a base class are not allowed Saya melihat alasan untuk ini, tetapi saya kecewa, karena akan sangat menyenangkan jika memungkinkan ini ..
Henrik

@ MEC: Saya perhatikan Anda membuang bagian `where T: MyBaseClass` dan menambahkan if (type.BaseType != null)Pernyataan relatif terhadap A. Markus Knappen Johansson Mengapa demikian? Itu berarti itu akan memungkinkan Jenis Panggilan yang tidak Berasal dari MyBaseClass (atau apa pun dalam hal ini). Saya menyadari itu masih akan menyebabkan kesalahan kompilator jika Ditugaskan ke myDerivedObject, tetapi jika itu hanya digunakan sebagai Ekspresi, itu akan mengkompilasi dan pada saat run-time hanya membuat myDerivedObject tanpa data disalin dari "myBaseObject". Saya tidak bisa membayangkan kasus penggunaan untuk itu.
Tom

@Tom, telat balas, tapi kupikir mungkin masih berguna. Tanggapan terbaik untuk pertanyaan Anda mungkin akan mengatakan bahwa nama "As" sebaiknya "AsOrDefault". Pada dasarnya kita dapat mengambil hasil ini dan membandingkannya dengan Default seperti yang kita lakukan saat menggunakan SingleOrDefault atau FirstOrDefault Linq.
MEC

7

Tidak itu tidak mungkin, karena itu kesalahan runtime Anda.

Tapi Anda bisa menetapkan sebuah instance dari kelas turunan ke variabel tipe kelas dasar.


7

Solusi dengan JsonConvert (bukan typecast)

Hari ini saya menghadapi masalah yang sama dan saya menemukan solusi sederhana dan cepat untuk masalah penggunaan JsonConvert.

var base = new BaseClass();
var json = JsonConvert.SerializeObject(base);
DerivedClass derived = JsonConvert.DeserializeObject<DerivedClass>(json);

Saya menjawab ini lagi di bawah dengan metode ekstensi. Ya, inilah jawabannya.
Patrick Knott

5

Seperti yang dikatakan semua orang di sini, itu tidak mungkin secara langsung.

Metode yang saya suka dan agak bersih, adalah menggunakan Pemeta Objek seperti AutoMapper .

Ini akan melakukan tugas menyalin properti dari satu contoh ke contoh lainnya (Tidak harus tipe yang sama) secara otomatis.


3

Memperluas jawaban @ ybo - itu tidak mungkin karena instance yang Anda miliki dari kelas dasar sebenarnya bukan turunan dari kelas turunan. Ia hanya tahu tentang anggota kelas dasar, dan tidak tahu apa-apa tentang kelas turunan.

Alasan Anda dapat mentransmisikan instance dari kelas turunan ke instance kelas dasar adalah karena kelas turunan sebenarnya sudah merupakan turunan dari kelas dasar, karena sudah memiliki anggota tersebut. Kebalikannya tidak bisa dikatakan.


3

Anda dapat mentransmisikan variabel yang diketik sebagai kelas dasar ke jenis kelas turunan; namun, dengan kebutuhan ini akan melakukan pemeriksaan runtime, untuk melihat apakah objek aktual yang terlibat memiliki tipe yang benar.

Setelah dibuat, jenis objek tidak dapat diubah (paling tidak, mungkin ukurannya tidak sama). Namun, Anda dapat mengonversi sebuah instance, membuat instance baru dari tipe kedua - tetapi Anda perlu menulis kode konversi secara manual.


2

Tidak, tidak mungkin.

Pertimbangkan skenario di mana ACBus adalah kelas turunan Bus kelas dasar. ACBus memiliki fitur seperti TurnOnAC dan TurnOffAC yang beroperasi pada bidang bernama ACState. TurnOnAC menyetel ACState ke aktif dan TurnOffAC menyetel ACState ke nonaktif. Jika Anda mencoba menggunakan fitur TurnOnAC dan TurnOffAC di Bus, itu tidak masuk akal.


2
class Program
{
    static void Main(string[] args)
    {
        a a1 = new b();  
        a1.print();  
    }
}
class a
{
    public a()
    {
        Console.WriteLine("base class object initiated");
    }
    public void print()
    {
        Console.WriteLine("base");
    }
}
class b:a
{
    public b()
    {
        Console.WriteLine("child class object");
    }
    public void print1()
    {
        Console.WriteLine("derived");
    }
}

}

ketika kita membuat objek kelas anak, objek kelas dasar dimulai secara otomatis sehingga variabel referensi kelas dasar dapat menunjuk ke objek kelas anak.

tetapi tidak sebaliknya karena variabel referensi kelas anak tidak dapat menunjuk ke objek kelas dasar karena tidak ada objek kelas anak yang dibuat.

dan juga perhatikan bahwa variabel referensi kelas dasar hanya dapat memanggil anggota kelas dasar.


2

Sebenarnya ADA cara untuk melakukan ini. Pikirkan tentang bagaimana Anda dapat menggunakan Newtonsoft JSON untuk deserialisasi objek dari json. Ini akan (atau setidaknya dapat) mengabaikan elemen yang hilang dan mengisi semua elemen yang diketahui.

Jadi, inilah cara saya melakukannya. Contoh kode kecil akan mengikuti penjelasan saya.

  1. Buat instance objek Anda dari kelas dasar dan isilah sesuai dengan itu.

  2. Menggunakan kelas "jsonconvert" dari Newtonsoft json, membuat serial objek itu menjadi string json.

  3. Sekarang buat objek sub kelas Anda dengan deserialisasi dengan string json yang dibuat pada langkah 2. Ini akan membuat turunan dari sub kelas Anda dengan semua properti dari kelas dasar.

Ini bekerja seperti pesona! Jadi .. kapan ini berguna? Beberapa orang bertanya kapan ini masuk akal dan menyarankan untuk mengubah skema OP untuk mengakomodasi fakta bahwa Anda tidak dapat melakukan ini secara native dengan warisan kelas (dalam .Net).

Dalam kasus saya, saya memiliki kelas pengaturan yang berisi semua pengaturan "dasar" untuk layanan. Layanan tertentu memiliki lebih banyak opsi dan berasal dari tabel DB yang berbeda, sehingga kelas tersebut mewarisi kelas dasar. Mereka semua memiliki serangkaian opsi yang berbeda. Jadi, saat mengambil data untuk layanan, akan jauh lebih mudah untuk mengisi FIRST nilai menggunakan instance objek dasar. Salah satu metode untuk melakukan ini dengan kueri DB tunggal. Tepat setelah itu, saya membuat objek subkelas menggunakan metode yang diuraikan di atas. Saya kemudian membuat kueri kedua dan mengisi semua nilai dinamis pada objek subkelas.

Output akhir adalah kelas turunan dengan semua opsi yang ditetapkan. Mengulangi ini untuk sub kelas baru tambahan hanya membutuhkan beberapa baris kode. Ini sederhana, dan menggunakan paket yang telah dicoba dan diuji (Newtonsoft) untuk membuat keajaiban bekerja.

Kode contoh ini adalah vb.Net, tetapi Anda dapat dengan mudah mengubahnya ke c #.

' First, create the base settings object.
    Dim basePMSettngs As gtmaPayMethodSettings = gtmaPayments.getBasePayMethodSetting(payTypeId, account_id)
    Dim basePMSettingsJson As String = JsonConvert.SerializeObject(basePMSettngs, Formatting.Indented)

    ' Create a pmSettings object of this specific type of payment and inherit from the base class object
    Dim pmSettings As gtmaPayMethodAimACHSettings = JsonConvert.DeserializeObject(Of gtmaPayMethodAimACHSettings)(basePMSettingsJson)

menggunakan C # dan Newtonsoft.Json: var destObject = JsonConvert.DeserializeObject<DestinationType>(JsonConvert.SerializeObject(srcObject));. Saya hanya akan menggunakan ini untuk pengujian unit dan "peretasan" non-produksi lainnya!
thinkOfaNumber

2

Anda dapat menggunakan Extention:

public static void CopyOnlyEqualProperties<T>(this T objDest, object objSource) where T : class
    {
        foreach (PropertyInfo propInfo in typeof(T).GetProperties())
            if (objSource.GetType().GetProperties().Any(z => z.Name == propInfo.Name && z.GetType() == propInfo.GetType()))
                propInfo.SetValue(objDest, objSource.GetType().GetProperties().First(z => z.Name == propInfo.Name && z.GetType() == propInfo.GetType()).GetValue(objSource));
    }

Dalam kode:

public class BaseClass
{
  public string test{ get; set;}
}
public Derived : BaseClass
{
//Some properies
}

public void CopyProps()
{
   BaseClass baseCl =new BaseClass();
   baseCl.test="Hello";
   Derived drv=new Derived();
   drv.CopyOnlyEqualProperties(baseCl);
   //Should return Hello to the console now in derived class.
   Console.WriteLine(drv.test);

}

1

Mungkin tidak relevan, tetapi saya dapat menjalankan kode pada objek turunan berdasarkan basisnya. Ini jelas lebih hacky daripada yang saya inginkan, tetapi berhasil:

public static T Cast<T>(object obj)
{
    return (T)obj;
}

...

//Invoke parent object's json function
MethodInfo castMethod = this.GetType().GetMethod("Cast").MakeGenericMethod(baseObj.GetType());
object castedObject = castMethod.Invoke(null, new object[] { baseObj });
MethodInfo jsonMethod = baseObj.GetType ().GetMethod ("ToJSON");
return (string)jsonMethod.Invoke (castedObject,null);

1

Anda dapat melakukan ini dengan menggunakan generik.

public class BaseClass
{
    public int A { get; set; }
    public int B { get; set; }
    private T ConvertTo<T>() where T : BaseClass, new()
    {
         return new T
         {
             A = A,
             B = B
         }
    }

    public DerivedClass1 ConvertToDerivedClass1()
    {
         return ConvertTo<DerivedClass1>();
    }

    public DerivedClass2 ConvertToDerivedClass2()
    {
         return ConvertTo<DerivedClass2>();
    }
}

public class DerivedClass1 : BaseClass
{
    public int C { get; set; }
}

public class DerivedClass2 : BaseClass
{
    public int D { get; set; }
}

Anda mendapatkan tiga manfaat menggunakan pendekatan ini.

  1. Anda tidak menduplikasi kode
  2. Anda tidak menggunakan refleksi (yang lambat)
  3. Semua konversi Anda ada di satu tempat

1

Saya tahu ini sudah tua tetapi saya telah menggunakan ini dengan sukses cukup lama.

   private void PopulateDerivedFromBase<TB,TD>(TB baseclass,TD derivedclass)
    {
        //get our baseclass properties
        var bprops = baseclass.GetType().GetProperties();
        foreach (var bprop in bprops)
        {
            //get the corresponding property in the derived class
            var dprop = derivedclass.GetType().GetProperty(bprop.Name);
            //if the derived property exists and it's writable, set the value
            if (dprop != null && dprop.CanWrite)
                dprop.SetValue(derivedclass,bprop.GetValue(baseclass, null),null);
        }
    } 

1

Saya menggabungkan beberapa bagian dari jawaban sebelumnya (terima kasih kepada para penulis tersebut) dan menyusun kelas statis sederhana dengan dua metode yang kami gunakan.

Ya, itu sederhana, tidak itu tidak mencakup semua skenario, ya itu bisa diperluas dan dibuat lebih baik, tidak itu tidak sempurna, ya itu mungkin bisa dibuat lebih efisien, bukan itu bukan yang terbaik sejak roti iris, ya ada full-on pemeta objek paket nuget yang kuat di luar sana yang jauh lebih baik untuk penggunaan berat, dll, yada yada - tetapi ini berfungsi untuk kebutuhan dasar kita :)

Dan tentu saja ia akan mencoba memetakan nilai dari objek apa pun ke objek apa pun, diturunkan atau tidak (hanya properti publik yang diberi nama sama saja - mengabaikan yang lainnya).

PEMAKAIAN:

SesameStreetCharacter puppet = new SesameStreetCharacter() { Name = "Elmo", Age = 5 };

// creates new object of type "RealPerson" and assigns any matching property 
// values from the puppet object 
// (this method requires that "RealPerson" have a parameterless constructor )
RealPerson person = ObjectMapper.MapToNewObject<RealPerson>(puppet);

// OR

// create the person object on our own 
// (so RealPerson can have any constructor type that it wants)
SesameStreetCharacter puppet = new SesameStreetCharacter() { Name = "Elmo", Age = 5 };
RealPerson person = new RealPerson("tall") {Name = "Steve"};

// maps and overwrites any matching property values from 
// the puppet object to the person object so now our person's age will get set to 5 and
// the name "Steve" will get overwritten with "Elmo" in this example
ObjectMapper.MapToExistingObject(puppet, person);

KELAS UTILITAS STATIK:

public static class ObjectMapper
{
    // the target object is created on the fly and the target type 
    // must have a parameterless constructor (either compiler-generated or explicit) 
    public static Ttarget MapToNewObject<Ttarget>(object sourceobject) where Ttarget : new()
    {
        // create an instance of the target class
        Ttarget targetobject = (Ttarget)Activator.CreateInstance(typeof(Ttarget));

        // map the source properties to the target object
        MapToExistingObject(sourceobject, targetobject);

        return targetobject;
    }

    // the target object is created beforehand and passed in
    public static void MapToExistingObject(object sourceobject, object targetobject)
    {
        // get the list of properties available in source class
        var sourceproperties = sourceobject.GetType().GetProperties().ToList();

        // loop through source object properties
        sourceproperties.ForEach(sourceproperty => {

            var targetProp = targetobject.GetType().GetProperty(sourceproperty.Name);

            // check whether that property is present in target class and is writeable
            if (targetProp != null && targetProp.CanWrite)
            {
                // if present get the value and map it
                var value = sourceobject.GetType().GetProperty(sourceproperty.Name).GetValue(sourceobject, null);
                targetobject.GetType().GetProperty(sourceproperty.Name).SetValue(targetobject, value, null);
            }
        });
    }
}

1

Anda dapat menggunakan konstruktor salinan yang segera memanggil konstruktor instans, atau jika konstruktor instans Anda melakukan lebih dari tugas, maka konstruktor salinan menetapkan nilai yang masuk ke instans.

class Person
{
    // Copy constructor 
    public Person(Person previousPerson)
    {
        Name = previousPerson.Name;
        Age = previousPerson.Age;
    }

    // Copy constructor calls the instance constructor.
    public Person(Person previousPerson)
        : this(previousPerson.Name, previousPerson.Age)
    {
    }

    // Instance constructor.
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public int Age { get; set; }

    public string Name { get; set; }
}

Merujuk Dokumentasi Microsoft C # di bawah Pembuat untuk contoh ini yang pernah mengalami masalah ini di masa lalu.


0

Solusi lain adalah menambahkan metode ekstensi seperti ini:

 public static void CopyProperties(this object destinationObject, object sourceObject, bool overwriteAll = true)
        {
            try
            {
                if (sourceObject != null)
                {
                    PropertyInfo[] sourceProps = sourceObject.GetType().GetProperties();
                    List<string> sourcePropNames = sourceProps.Select(p => p.Name).ToList();
                    foreach (PropertyInfo pi in destinationObject.GetType().GetProperties())
                    {
                        if (sourcePropNames.Contains(pi.Name))
                        {
                            PropertyInfo sourceProp = sourceProps.First(srcProp => srcProp.Name == pi.Name);
                            if (sourceProp.PropertyType == pi.PropertyType)
                                if (overwriteAll || pi.GetValue(destinationObject, null) == null)
                                {
                                    pi.SetValue(destinationObject, sourceProp.GetValue(sourceObject, null), null);
                                }
                        }
                    }
                }
            }
            catch (ApplicationException ex)
            {
                throw;
            }
        }

kemudian miliki konstruktor di setiap kelas turunan yang menerima kelas dasar:

  public class DerivedClass: BaseClass
    { 
        public DerivedClass(BaseClass baseModel)
        {
            this.CopyProperties(baseModel);
        }
    }

Ini juga akan secara opsional menimpa properti tujuan jika sudah disetel (bukan null) atau belum.


0

Apakah mungkin untuk menetapkan objek kelas dasar ke referensi kelas turunan dengan typecast eksplisit di C # ?.

Tidak hanya eksplisit, tetapi juga konversi implisit dimungkinkan.

Bahasa C # tidak mengizinkan operator konversi seperti itu, tetapi Anda masih dapat menulisnya menggunakan C # murni dan mereka berfungsi. Perhatikan bahwa kelas yang mendefinisikan operator konversi implisit ( Derived) dan kelas yang menggunakan operator ( Program) harus didefinisikan dalam rakitan terpisah (misalnya Derivedkelas dalam a library.dllyang direferensikan dengan program.exememuat Programkelas).

//In library.dll:
public class Base { }

public class Derived {
    [System.Runtime.CompilerServices.SpecialName]
    public static Derived op_Implicit(Base a) {
        return new Derived(a); //Write some Base -> Derived conversion code here
    }

    [System.Runtime.CompilerServices.SpecialName]
    public static Derived op_Explicit(Base a) {
        return new Derived(a); //Write some Base -> Derived conversion code here
    }
}

//In program.exe:
class Program {
    static void Main(string[] args) {
        Derived z = new Base(); //Visual Studio can show squiggles here, but it compiles just fine.
    }
}

Ketika Anda mereferensikan pustaka menggunakan Referensi Proyek di Visual Studio, VS memperlihatkan coretan ketika Anda menggunakan konversi implisit, tapi itu mengkompilasi dengan baik. Jika Anda hanya mereferensikan library.dll, tidak ada coretan.


Sihir hitam apa ini?!? Juga, bagaimana "Turunan z = Basis baru ()" membantu saya melakukan "BaseCls baseObj; DerivedCls turunanObj; turunanObj = (DerivedCls) baseObj" (OP's Q)? Juga, apa yang dilakukan System.Runtime.CompilerServices.SpecialNameAtribut? Dokumen untuk setiap versi dari yang paling awal tersedia (2.0) hingga "versi saat ini" (4.6? "Siapa? Siapa?") Tidak mengatakan apa fungsinya, tetapi katakanlah "Kelas SpecialNameAttribute saat ini tidak digunakan dalam .NET Kerangka kerja, tetapi dicadangkan untuk penggunaan di masa mendatang. ". Lihat: [link] ( msdn.microsoft.com/en-us/library/ms146064(v=vs.100).aspx ).
Tom

> "Ilmu hitam apa ini?!?" Itu disebut .Net Framework (CLR, IL, BCL). Set fitur bahasa IL, C # dan VB tidak sama. Ada beberapa fitur di VB yang tidak didukung C #. Ada fitur dalam IL yang tidak didukung C #. Ada batasan di C # yang agak sewenang-wenang dan tidak ada di IL yang mendasari (seperti where T : Delegateproperti parametrized alias pengindeks dll dll).
Ark-kun

> "Juga, bagaimana" Derived z = new Base () "membantu saya melakukan" BaseCls baseObj; DerivedCls intendedObj; turunanObj = (DerivedCls) baseObj "(Q OP)?" Itu terjadi begitu saja. Ini memecahkan pertanyaan OP. Dan Anda bahkan tidak membutuhkan pemeran eksplisit.
Ark-kun

> what does System.Runtime.CompilerServices.SpecialName Attribute do?- Ini digunakan untuk menandai metode yang dihasilkan oleh beberapa konstruk kenyamanan khusus dari bahasa .Net tingkat tinggi: pengakses properti, pengakses acara, konstruktor, operator, pengindeks, dll. Kecuali jika metode IL ditandai dengan specialnameitu tidak akan terlihat sebagai properti / acara / konstruktor dan itu hanya akan dikenali sebagai metode normal. Menandai secara manual metode yang dinamai dengan tepat dengan atribut ini hanya secara manual melakukan sedikit tugas kompiler.
Ark-kun

VB.Net memiliki operator daya. C # tidak. Bagaimana Anda membebani operator daya di C # untuk digunakan di VB.Net? Cukup tentukan op_Exponentmetode dan tandai dengan specialnameatribut.
Ark-kun

0

Bagaimana tentang:

public static T As<T>(this object obj)
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
    }

0

Cara terbaik untuk menambahkan semua properti dasar ke item turunan adalah menggunakan refleksi di costructor. Coba kode ini, tanpa membuat metode atau contoh.

    public Derived(Base item) :base()
    {

        Type type = item.GetType();

        System.Reflection.PropertyInfo[] properties = type.GetProperties();
        foreach (var property in properties)
        {
            try
            {
                property.SetValue(this, property.GetValue(item, null), null);
            }
            catch (Exception) { }
        }

    }

0

Saya tidak setuju bahwa itu tidak mungkin. Anda bisa melakukannya seperti ini:

public class Auto 
{ 
    public string Make {get; set;}
    public string Model {get; set;}
}

public class Sedan : Auto
{ 
    public int NumberOfDoors {get; set;}
}

public static T ConvertAuto<T>(Sedan sedan) where T : class
{
    object auto = sedan;
    return (T)loc;
}

Pemakaian:

var sedan = new Sedan();
sedan.NumberOfDoors = 4;
var auto = ConvertAuto<Auto>(sedan);

var auto =masih tipesedan
bendecko

0

Beginilah cara saya memecahkan masalah ini untuk ladang. Anda dapat melakukan iterasi yang sama melalui properti jika Anda mau. Anda mungkin ingin melakukan beberapa pemeriksaan untuk nulldll, tetapi inilah idenya.

 public static DerivedClass ConvertFromBaseToDerived<BaseClass, DerivedClass>(BaseClass baseClass)
            where BaseClass : class, new()
            where DerivedClass : class, BaseClass, new()
        {
            DerivedClass derived = (DerivedClass)Activator.CreateInstance(typeof(DerivedClass));
            derived.GetType().GetFields().ToList().ForEach(field =>
            {
                var base_ = baseClass.GetType().GetField(field.Name).GetValue(baseClass);
                field.SetValue(derived, base_);

            });

            return derived;
        }

0

Anda cukup membuat serial objek dasar ke JSON dan kemudian deserialisasi ke objek turunan.


0

Bukan dalam Pengertian Tradisional ... Ubah ke Json, lalu ke objek Anda, dan boom, selesai! Jesse di atas memiliki jawaban yang diposting terlebih dahulu, tetapi tidak menggunakan metode ekstensi ini yang membuat prosesnya jauh lebih mudah. Buat beberapa metode ekstensi:

    public static string ConvertToJson<T>(this T obj)
    {
        return JsonConvert.SerializeObject(obj);
    }
    public static T ConvertToObject<T>(this string json)
    {
        if (string.IsNullOrEmpty(json))
        {
            return Activator.CreateInstance<T>();
        }
        return JsonConvert.DeserializeObject<T>(json);
    }

Tempatkan mereka di kotak peralatan Anda selamanya, maka Anda selalu dapat melakukan ini:

var derivedClass = baseClass.ConvertToJson().ConvertToObject<derivedClass>();

Ah, kekuatan JSON.

Ada beberapa masalah dengan pendekatan ini: Kami benar-benar membuat objek baru, bukan mentransmisi, yang mungkin menjadi masalah atau tidak. Bidang pribadi tidak akan ditransfer, konstruktor dengan parameter tidak akan dipanggil, dll. Ada kemungkinan bahwa beberapa json anak tidak akan ditetapkan. Aliran tidak ditangani secara bawaan oleh JsonConvert. Namun, jika kelas kita tidak bergantung pada bidang privat dan konstruktor, ini adalah metode yang sangat efektif untuk memindahkan data dari kelas ke kelas tanpa pemetaan dan memanggil konstruktor, yang merupakan alasan utama mengapa kita ingin melakukan cast di tempat pertama.


Ini tidak melakukan apa yang diminta OP. Apa yang Anda lakukan adalah membuat objek baru dengan tipe yang benar untuk variabel, menggunakan data dari objek asli dengan tipe yang salah. Ini mungkin atau mungkin tidak bekerja, tapi bagaimanapun juga, itu pasti tidak menugaskan objek dari tipe kelas dasar ke variabel dari tipe turunan.
Lasse V. Karlsen

Saya menjawab pertanyaan: Apakah mungkin untuk menetapkan objek kelas dasar ke referensi kelas turunan dengan typecast eksplisit? Dengan mengatakan tidak. Saya memberikan alternatif yang benar-benar berfungsi dan tidak terlalu membingungkan daripada obat generik. Seperti yang dilambangkan berkali-kali di atas, ini dapat menyebabkan masalah dalam menetapkan ke properti kelas turunan dari kelas dasar, namun, ini persis seperti cara kerjanya (dan dilakukannya di apis) jika memungkinkan. Hanya karena jawaban saya dapat digunakan dari jenis yang "salah" tidak berarti jawaban itu tidak dapat digunakan untuk jenis yang "benar". @ LasseV.Karlsen harap cabut peringkat negatif Anda.
Patrick Knott

Tidak seperti kebanyakan jawaban di sini yang daisy chain JsonConverts, saya menunjukkan bagaimana menangani null juga.
Patrick Knott

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.