Açık bir typecast ile türetilmiş bir sınıf referansına temel bir sınıf nesnesi atamak mümkün müdür?


89

C # 'da açık bir typecast ile türetilmiş bir sınıf referansına temel bir sınıf nesnesi atamak mümkün müdür ?.

Denedim ve bir çalışma zamanı hatası oluşturuyor.

Yanıtlar:


100

Hayır. Türetilmiş bir sınıfa yapılan başvuru, aslında türetilmiş sınıfın (veya null) bir örneğine başvurmalıdır. Aksi takdirde nasıl davranmasını beklersiniz?

Örneğin:

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

Temel türün bir örneğini türetilmiş türe dönüştürebilmek istiyorsanız, uygun bir türetilmiş tür örneği oluşturmak için bir yöntem yazmanızı öneririm. Veya miras ağacınıza tekrar bakın ve yeniden tasarlamaya çalışın, böylece ilk etapta bunu yapmanıza gerek kalmaz.


72
@Mike: Kod çok iyi derleniyor. Yürütme zamanında
düşse

1
O zaman Base b = new Derived () 'i yazdığımızda tam olarak ne olur; ? Hem temel hem de türetilmiş sınıf için nesneler yaratacak mı?
Ashif Nataliya

3
@Akie: Hayır, tek bir tür nesnesi oluşturur Derived, ancak bir Derivedreferansı referans olarak değerlendirebilirsiniz Base.
Jon Skeet

Öyleyse, bu iki ifade için ortaya çıkan nesnede herhangi bir fark var mı? Temel b = yeni Baz () ve Temel b = yeni Türetilmiş ()? birini diğerine göre kullanmanın faydası nedir?
Ashif Nataliya

4
@Akie: Evet, biri örneğini Base, diğeri örneğini oluşturuyor Derived. Üzerine bgeçersiz kılınan bir sanal yöntemi çağırırsanız Derived, Derivedörneğiniz varsa davranışı görürsünüz Derived. Ancak bir Stack Overflow yorum dizisindeki ayrıntılara girmek gerçekten uygun değildir - bu oldukça temel bir konu olduğu için gerçekten iyi bir C # kitabı veya öğretici okumalısınız.
Jon Skeet

47

Hayır, bunu türetilmiş bir sınıf referansına atamak, "Temel sınıf türetilmiş sınıfın tam olarak ikame edilmesidir, türetilmiş sınıfın yapabildiği her şeyi yapabilir" demek gibi olacağından bu mümkün değildir, bu da genel olarak türetilmiş sınıflar sunduğundan bu doğru değildir temel sınıflarından daha fazla işlevsellik (en azından kalıtımın arkasındaki fikir budur).

Türetilmiş sınıfta, değerleri kopyalayarak bir temel sınıf nesnesini parametre olarak alan bir yapıcı yazabilirsiniz.

Bunun gibi bir şey:

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

Bu durumda, temel nesneyi kopyalar ve türetilmiş üyeler için varsayılan değerlere sahip tamamen işlevsel bir türetilmiş sınıf nesnesi alırsınız. Bu şekilde Jon Skeet'in işaret ettiği problemden de kurtulabilirsiniz:

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

Bu sorunu yaşadım ve bir tür parametresi alan ve mevcut nesneyi bu türe dönüştüren bir yöntem ekleyerek çözdüm.

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

Bu, kodunuzda şu şekilde kullanabileceğiniz anlamına gelir:

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

Türetilmiş sınıfa eşlemek istediğiniz değerler olduğundan, özellikleri almak ve ayarlamak için geçerli sınıfın türünü (temel sınıf) kullanmalısınız.
Bowofola

1
Türetilmiş türde yazılamayan özellikleriniz varsa, muhtemelen şu şekilde değiştirmeniz gerekir: if (property.CanWrite) property.SetValue (örnek, özellik.GetValue (this, null), null);
user3478586

10

Diğerlerinin cevapladığı gibi, Hayır.

Türetilmiş bir tür olarak bir temel türü kullanmam gerektiğinde, bu talihsiz durumlarda aşağıdaki kodu kullanıyorum. Evet, bu Liskov İkame İlkesinin (LSP) ihlalidir ve evet çoğu zaman miras yerine kompozisyonu tercih ederiz. Orijinal cevabına dayanan Markus Knappen Johansson'a destek.

Temel sınıftaki bu kod:

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

Şunları sağlar:

    derivedObject = baseObect.As<derivedType>()

Yansıma kullandığı için "pahalıdır". Buna göre kullanın.


Bunu henüz denedim ve düşündüm ki, açık operatörü (ve ayrıca örtük operatörü) aşırı yükleyerek daha da geliştirilebilir .. ama - Derleyici buna izin vermiyor: user-defined conversions to or from a base class are not allowed Bunun nedenlerini görüyorum ama hayal kırıklığına uğradım, buna izin verseydi çok eğlenceli olurdu ..
Henrik

@MEC: "T: MyBaseClass" bölümünü bıraktığınızı ve if (type.BaseType != null)Markus Knappen Johansson'un A'sına göre Beyanı eklediğinizi fark ettim . Neden bu? Bu, MyBaseClass'tan (veya bu konuyla ilgili herhangi bir şeyden) Türetilmeyen Çağrılarda bir Türe izin vereceği anlamına gelir. MyDerivedObject'e atanırsa yine de bir derleyici hatasına neden olacağının farkındayım, ancak sadece bir İfade olarak kullanılıyorsa, derlenecek ve çalışma zamanında "myBaseObject" den herhangi bir veri kopyalanmadan bir myDerivedObject oluşturacaktır. Bunun için bir kullanım durumu düşünemiyorum.
Tom

@ Tom, geç cevap verdim, ancak yine de yararlı olabileceğini düşündüm. Sorunuza verilecek en iyi yanıt muhtemelen "As" adının "AsOrDefault" olması daha iyi olacağını söylemektir. Esasen bu sonucu alıp Linq'in SingleOrDefault veya FirstOrDefault'unu kullanırken yaptığımız gibi bir Varsayılan ile karşılaştırabiliriz.
MEC

7

Hayır mümkün değil, bu nedenle çalışma zamanı hatanız.

Ancak, türetilmiş bir sınıfın bir örneğini temel sınıf türündeki bir değişkene atayabilirsiniz.


7

JsonConvert ile çözüm (typecast yerine)

Bugün aynı sorunla karşılaştım ve kullanarak soruna basit ve hızlı bir çözüm buldum JsonConvert.

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

Bunu aşağıda uzatma yöntemleriyle tekrar cevapladım. Evet, cevap bu.
Patrick Knott

5

Buradaki herkesin dediği gibi, bu doğrudan mümkün değil.

Tercih ettiğim ve oldukça temiz olan yöntem AutoMapper gibi bir Object Mapper kullanmaktır .

Özelliklerin bir örnekten diğerine (aynı tip olması gerekmez) otomatik olarak kopyalanması görevini yerine getirir.


3

@ Ybo'nun cevabını genişletmek - bu mümkün değildir, çünkü temel sınıfın sahip olduğunuz örneği aslında türetilmiş sınıfın bir örneği değildir. Yalnızca temel sınıfın üyelerini bilir ve türetilmiş sınıfın üyeleri hakkında hiçbir şey bilmez.

Türetilmiş sınıfın bir örneğini temel sınıfın bir örneğine dönüştürebilmenizin nedeni, türetilmiş sınıfın aslında zaten bu üyelere sahip olduğundan temel sınıfın bir örneği olmasıdır. Bunun tersi söylenemez.


3

Temel sınıf olarak yazılan bir değişkeni türetilmiş bir sınıfın türüne çevirebilirsiniz ; ancak, zorunlu olarak bu, ilgili gerçek nesnenin doğru türde olup olmadığını görmek için bir çalışma zamanı kontrolü yapacaktır.

Oluşturulduktan sonra , bir nesnenin türü değiştirilemez (en önemlisi, aynı boyutta olmayabilir). Bununla birlikte, ikinci türün yeni bir örneğini oluşturarak bir örneği dönüştürebilirsiniz - ancak dönüştürme kodunu manuel olarak yazmanız gerekir.


2

Hayır, bu mümkün değil.

Bir ACBus'un türetilmiş bir temel sınıf veri yolu olduğu bir senaryo düşünün. ACBus, ACState adlı bir alanda çalışan TurnOnAC ve TurnOffAC gibi özelliklere sahiptir. TurnOnAC, ACState'i açık olarak ayarlar ve TurnOffAC, ACState'i kapalı olarak ayarlar. Veriyolunda TurnOnAC ve TurnOffAC özelliklerini kullanmaya çalışırsanız, bu bir anlam ifade etmiyor.


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

}

Bir alt sınıf nesnesi oluşturduğumuzda, temel sınıf nesnesi otomatik olarak başlatılır, böylece temel sınıf başvurusu değişkeni alt sınıf nesnesine işaret edebilir.

ancak bunun tersi olmaz çünkü bir alt sınıf referans değişkeni temel sınıf nesnesine işaret edemez çünkü hiçbir alt sınıf nesnesi oluşturulmaz.

ve ayrıca temel sınıf referans değişkeninin yalnızca temel sınıf üyesini çağırabileceğine dikkat edin.


2

Aslında bunu yapmanın bir yolu var. Bir nesneyi json'dan seri durumdan çıkarmak için Newtonsoft JSON'u nasıl kullanabileceğinizi düşünün. Eksik öğeleri görmezden gelir (veya en azından yapabilir) ve bildiği tüm öğeleri doldurur.

İşte bunu nasıl yaptım. Küçük bir kod örneği açıklamamı takip edecek.

  1. Temel sınıftan nesnenizin bir örneğini oluşturun ve buna göre doldurun.

  2. Newtonsoft json'un "jsonconvert" sınıfını kullanarak, bu nesneyi bir json dizesine serileştirin.

  3. Şimdi, 2. adımda oluşturulan json dizesi ile seriyi kaldırarak alt sınıf nesnenizi oluşturun. Bu, alt sınıfınızın temel sınıfın tüm özelliklerine sahip bir örneğini oluşturacaktır.

Bu bir cazibe gibi çalışıyor! Peki .. bu ne zaman yararlıdır? Bazı insanlar bunun ne zaman mantıklı olacağını sordu ve bunu sınıf kalıtımıyla (.Net'te) yerel olarak yapamayacağınız gerçeğine uyum sağlamak için OP'nin şemasını değiştirmeyi önerdiler.

Benim durumumda, bir hizmet için tüm "temel" ayarları içeren bir ayarlar sınıfım var. Belirli hizmetlerin daha fazla seçeneği vardır ve bunlar farklı bir DB tablosundan gelir, bu nedenle bu sınıflar temel sınıfı miras alır. Hepsinin farklı seçenekleri vardır. Dolayısıyla, bir hizmet için verileri alırken, değerleri İLK olarak, temel nesnenin bir örneğini kullanarak doldurmak çok daha kolaydır. Bunu tek bir DB sorgusuyla yapmak için bir yöntem. Hemen ardından alt sınıf nesnesini yukarıda anlattığım yöntemi kullanarak oluşturuyorum. Daha sonra ikinci bir sorgu yapıyorum ve alt sınıf nesnesindeki tüm dinamik değerleri dolduruyorum.

Son çıktı, tüm seçeneklerin ayarlandığı türetilmiş bir sınıftır. Ek yeni alt sınıflar için bunu tekrarlamak yalnızca birkaç satır kod gerektirir. Çok basit ve sihrin çalışması için çok denenmiş ve test edilmiş bir paket (Newtonsoft) kullanıyor.

Bu örnek kod vb.Net'tir, ancak kolayca c # koduna dönüştürebilirsiniz.

' 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)

C # ve Newtonsoft.Json kullanarak: var destObject = JsonConvert.DeserializeObject<DestinationType>(JsonConvert.SerializeObject(srcObject));. Bunu yalnızca birim testleri ve diğer üretim dışı "hackleme" için kullanırım!
thinkOfaNumber

2

Bir Uzantı kullanabilirsiniz:

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

Kodda:

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

Alakalı olmayabilir, ancak kodu tabanına göre türetilmiş bir nesnede çalıştırabildim. Kesinlikle istediğimden daha karmaşık ama işe yarıyor:

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

Bunu jenerik kullanarak yapabilirsiniz.

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

Bu yaklaşımı kullanarak üç avantaj elde edersiniz.

  1. Kodu çoğaltmıyorsunuz
  2. Yansıma kullanmıyorsunuz (ki bu yavaş)
  3. Tüm dönüşümleriniz tek bir yerde

1

Bunun eski olduğunu biliyorum ama bunu bir süredir başarıyla kullandım.

   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

Önceki cevapların bazı kısımlarını birleştirdim (bu yazarlar sayesinde) ve kullandığımız iki yöntemle basit bir statik sınıf oluşturdum.

Evet, basit, hayır tüm senaryoları kapsamıyor, evet genişletilebilir ve daha iyi hale getirilebilir, hayır mükemmel değil, evet muhtemelen daha verimli hale getirilebilir, hayır dilimlenmiş ekmekten bu yana en iyi şey değil, evet var yoğun kullanım için çok daha iyi olan tam kapsamlı nuget paketi nesne eşleyicileri, vb. yada yada - ama yine de temel ihtiyaçlarımız için çalışıyor :)

Ve elbette, herhangi bir nesneden türetilmiş olsun ya da olmasın herhangi bir nesneye değerleri eşlemeye çalışacaktır (tabii ki sadece aynı adı verilen genel özellikler - geri kalanını göz ardı eder).

KULLANIM:

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

STATİK KULLANIM SINIFI:

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

Örnek oluşturucuyu hemen çağıran bir kopya yapıcısı kullanabilirsiniz veya örnek oluşturucunuz atamalardan fazlasını yapıyorsa, kopya yapıcısının gelen değerleri örneğe atamasını sağlayabilirsiniz.

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

Geçmişte bu sorunu yaşamış olan bu örnek için Oluşturucu altındaki Microsoft C # Belgelerine başvurulmuştur .


0

Diğer bir çözüm ise şöyle bir uzantı yöntemi eklemektir:

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

daha sonra her türetilmiş sınıfta temel sınıfı kabul eden bir kurucuya sahip olun:

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

Ayrıca, önceden ayarlanmışsa (boş değilse) isteğe bağlı olarak hedef özelliklerin üzerine yazacaktır.


0

C # 'da açık bir typecast ile türetilmiş bir sınıf referansına temel bir sınıf nesnesi atamak mümkün müdür ?.

Yalnızca açık değil, aynı zamanda örtük dönüşümler de mümkündür.

C # dili, bu tür dönüştürme işleçlerine izin vermez, ancak bunları yine de saf C # kullanarak yazabilirsiniz ve çalışırlar. Örtük dönüştürme işlecini ( Derived) tanımlayan sınıf ve ( ) işlecini kullanan sınıfın Programayrı derlemelerde tanımlanması gerektiğine dikkat edin (örneğin, Derivedsınıf, sınıfı içererek library.dllbaşvurulan a içindedir).program.exeProgram

//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.
    }
}

Visual Studio'da Proje Başvurusunu kullanarak kitaplığa başvurduğunuzda, VS, örtük dönüştürmeyi kullandığınızda dalgalı çizgiler gösterir, ancak yalnızca iyi derler. Sadece referans verirseniz library.dll, dalgalı çizgiler yoktur.


Bu ne kara büyü?!? Ayrıca, "Türetilmiş z = new Base ()" bana "BaseCls baseObj; DerivedCls derivatedObj; DerivedObj = (DerivedCls) baseObj" (OP'nin Q'su) nasıl yardımcı olur? Ayrıca, System.Runtime.CompilerServices.SpecialNameÖznitelik ne yapar ? Kullanılabilir en eski sürümden (2.0) "geçerli sürüme" (4.6? "Kimse mi? Kimse mi?") Kadar her sürümün dokümanları ne yaptığını söylemiyor, ancak "SpecialNameAttribute sınıfı şu anda .NET'te kullanılmıyor Çerçeve, ancak gelecekteki kullanım için ayrılmıştır. ". Bakınız: [bağlantı] ( msdn.microsoft.com/en-us/library/ms146064(v=vs.100).aspx ).
Tom

> "Bu ne kara büyü?!?" Buna .Net Framework (CLR, IL, BCL) denir. IL, C # ve VB dillerinin özellik seti aynı değildir. VB'de C # 'ın desteklemediği özellikler vardır. IL'de C # 'ın desteklemediği özellikler vardır. C # 'da oldukça keyfi olan ve temel alınan IL'de bulunmayan kısıtlamalar vardır (benzer where T : Delegateveya parametreleştirilmiş özellikler, yani indeksleyiciler vb.).
Ark-kun

> "Ayrıca," Türetilmiş z = new Base () "bana nasıl yardımcı olur?" BaseCls baseObj; DerivedCls derivatedObj; türetilmişObj = (DerivedCls) baseObj "(OP'nin Q'su)?" Sadece yapar. OP'nin sorusunu çözer. Ve açık bir oyuncu kadrosuna bile ihtiyacınız yok.
Ark-kun

> what does System.Runtime.CompilerServices.SpecialName Attribute do?- Üst düzey .Net dillerinin bazı özel kolaylık yapıları tarafından üretilen yöntemleri işaretlemek için kullanılır: özellik erişimcileri, olay erişimcileri, kurucular, operatörler, indeksleyiciler vb. IL yöntemi ile işaretlenmedikçe specialnamegörülmez. özellik / olay / yapıcı olarak ve normal bir yöntem olarak kabul edilecektir. Uygun şekilde adlandırılmış yöntemleri bu öznitelikle manuel olarak işaretlemek, derleyicinin işinin bir kısmını elle yapmaktır.
Ark-kun

VB.Net'in güç operatörü vardır. C # yapmaz. VB.Net'te kullanmak için C #'da bir güç operatörünü nasıl aşırı yüklersiniz? Sadece bir op_Exponentyöntem tanımlayın ve onu specialnameöznitelikle işaretleyin .
Ark-kun

0

Peki ya:

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

0

Türetilmiş öğeye tüm temel özellikleri eklemenin en iyi yolu, oluşturucudaki yansımayı kullanmaktır. Yöntemler veya örnekler oluşturmadan bu kodu deneyin.

    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

Bunun mümkün olmadığına katılmıyorum. Bunu şu şekilde yapabilirsiniz:

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

Kullanım:

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

var auto =hala tiptesedan
bendecko

0

Bunu tarlalar için böyle çözdüm. İsterseniz aynı yinelemeyi özellikler aracılığıyla da yapabilirsiniz. nullVb için bazı kontroller yapmak isteyebilirsiniz ama fikir bu.

 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

Temel nesneyi JSON'a serileştirebilir ve ardından türetilmiş nesneye serisini kaldırabilirsiniz.


0

Geleneksel anlamda değil ... Json'a, sonra nesnenize dönüştürün ve boom, tamam! Yukarıdaki Jesse cevabı önce yayınladı, ancak süreci çok daha kolay hale getiren bu uzatma yöntemlerini kullanmadı. Birkaç uzatma yöntemi oluşturun:

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

Onları sonsuza kadar alet kutunuza koyun, sonra bunu her zaman yapabilirsiniz:

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

Ah, JSON'un gücü.

Bu yaklaşımla ilgili birkaç ipucu var: Gerçekten yeni bir nesne yaratıyoruz, döküm değil, önemli olabilir veya olmayabilir. Özel alanlar aktarılmayacak, parametrelere sahip kurucular çağrılmayacak, vb. Bazı alt jsonların atanmaması mümkündür. Akışlar doğuştan JsonConvert tarafından işlenmez. Bununla birlikte, sınıfımız özel alanlara ve kuruculara güvenmiyorsa, bu, verileri eşleme yapmadan ve kurucuları çağırmadan sınıftan sınıfa taşımak için çok etkili bir yöntemdir, bu da ilk etapta döküm yapmak istememizin ana nedenidir.


Bu, OP'nin istediğini yapmaz. Yaptığınız şey, yanlış türdeki orijinal nesneden gelen verileri kullanarak değişken için doğru türde yeni bir nesne oluşturmaktır. Bu işe yarayabilir veya çalışmayabilir, ancak her iki durumda da, kesinlikle türetilmiş tipteki bir değişkene temel sınıf türünden bir nesneyi atamamaktadır.
Lasse V. Karlsen

Şu soruyu yanıtladım: Açık bir typecast ile türetilmiş bir sınıf referansına temel bir sınıf nesnesi atamak mümkün müdür? Hayır diyerek. Kesinlikle işe yarayan ve jeneriklerden daha az kafa karıştırıcı olan bir alternatif sunuyorum. Yukarıda defalarca belirtildiği gibi, bir temel sınıftan türetilmiş bir sınıf özelliklerine atama sorunlarına neden olabilir, ancak mümkün olsaydı tam olarak bu şekilde çalışır (ve api'de yapar). Cevabımın "yanlış" bir türden kullanılabilmesi, "doğru" bir tür için kullanılamayacağı anlamına gelmez. @ LasseV.Karlsen lütfen negatif puanınızı geri çekin.
Patrick Knott

Buradaki JsonConverts papatya zinciri yanıtlarının çoğunun aksine, null ile nasıl başa çıkılacağını da gösteriyorum.
Patrick Knott

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.