Можно ли назначить объект базового класса для ссылки на производный класс с явным приведением типа? - PullRequest
72 голосов
/ 08 апреля 2009

Можно ли назначить объект базового класса для ссылки на производный класс с явной типизацией в C #?

Я пробовал это, и это создает ошибку во время выполнения.

Ответы [ 22 ]

2 голосов
/ 11 сентября 2016
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");
    }
}

}

когда мы создаем объект дочернего класса, объект базового класса запускается автоматически, поэтому ссылочная переменная базового класса может указывать на объект дочернего класса.

, но не наоборот, потому что ссылочная переменная дочернего класса не может указывать на объект базового класса, потому что объект дочернего класса не создается.

а также обратите внимание, что ссылочная переменная базового класса может вызывать только член базового класса.

1 голос
/ 25 июля 2018

Я знаю, что это старый, но я успешно использовал это в течение долгого времени.

   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 голос
/ 27 апреля 2018

Вы можете использовать расширение:

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

В коде:

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

}
0 голосов
/ 19 июля 2017

Вы можете сделать это, используя generic.

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

Используя этот подход, вы получаете три преимущества.

  1. Вы не дублируете код
  2. Вы не используете отражение (которое медленно)
  3. Все ваши конверсии в одном месте
0 голосов
/ 08 апреля 2009

Нет, см. Этот вопрос, который я задал - Обновление в .NET с использованием обобщений

Лучший способ - создать конструктор по умолчанию для класса, создать и затем вызвать Initialise метод

0 голосов
/ 16 апреля 2013

Можно ли назначить объект базового класса для ссылки на производный класс с явным приведением типа в C #?

Возможны не только явные, но и неявные преобразования.

Язык C # не разрешает такие операторы преобразования, но вы все равно можете написать их, используя чистый C #, и они работают. Обратите внимание, что класс, который определяет оператор неявного преобразования (Derived), и класс, который использует оператор (Program), должны быть определены в отдельных сборках (например, класс Derived находится в library.dll, на который ссылается program.exe, содержащий класс Program).

//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, VS показывает перекосы, когда вы используете неявное преобразование, но компилируется просто отлично. Если вы просто ссылаетесь на library.dll, то загогулинов нет.

0 голосов
/ 21 марта 2019

Лучший способ добавить все базовые свойства к производному элементу - использовать отражение в конструкторе. Попробуйте этот код, не создавая методы или экземпляры.

    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 голосов
/ 18 сентября 2018

Я объединил некоторые части предыдущих ответов (спасибо этим авторам) и собрал простой статический класс с двумя методами, которые мы используем.

Да, это просто, нет, это не охватывает все сценарии, да, его можно расширить и сделать лучше, нет, это не идеально, да, это можно сделать более эффективным, нет, это не самая лучшая вещь с нарезанного хлеба, да, есть полнофункциональные надежные средства отображения объектов пакета nuget, которые лучше подходят для интенсивного использования и т. д. и т. д., yada yada - но, тем не менее, это работает для наших основных потребностей :)

И, конечно, он будет пытаться отобразить значения из любого объекта в любой объект, производный или нет (конечно, только общедоступные свойства, которые называются одинаковыми - остальные игнорируются).

ИСПОЛЬЗОВАНИЕ:

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

СТАТИЧЕСКИЙ КЛАСС ПОЛЬЗОВАНИЯ:

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);
            }
        });
    }
}
0 голосов
/ 15 февраля 2019

Как насчет:

public static T As<T>(this object obj)
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
    }
0 голосов
/ 19 января 2015

Другое решение заключается в добавлении метода расширения следующим образом:

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

тогда есть конструктор в каждом производном классе, который принимает базовый класс:

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

Он также может при желании перезаписывать свойства назначения, если он уже установлен (не ноль) или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...