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

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

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

    Нет. Ссылка на производный class должна фактически ссылаться на экземпляр производного classа (или null). В противном случае, как вы ожидаете, что он будет себя вести?

    Например:

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

    Если вы хотите преобразовать экземпляр базового типа в производный тип, я предлагаю вам написать метод для создания соответствующего экземпляра производного типа. Или снова взгляните на свое дерево наследования и попробуйте перепроектировать, чтобы вам не нужно было это делать в первую очередь.

    Нет, это невозможно, так как назначение его в ссылку на производный class будет похоже на то, что «базовый class является полностью способной заменой производного classа, он может делать все, что может сделать производный class», что неверно, поскольку производные classы в целом предлагают больше функциональности, чем их базовый class (по крайней мере, это идея наследования).

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

    Что-то вроде этого:

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

    В этом случае вы скопируете базовый объект и получите полностью функциональный объект производного classа со значениями по умолчанию для производных членов. Таким образом, вы также можете избежать проблемы, отмеченной Джоном Скитом:

     Base b = new Base(); Dervided d = new Derived(); 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! 

    У меня была эта проблема и она была решена путем добавления метода, который принимает параметр типа и преобразует текущий объект в этот тип.

     public TA As() 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; } 

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

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

    Как и многие другие, нет.

    Я использую следующий код в тех неудачных случаях, когда мне нужно использовать базовый тип как производный тип. Да, это нарушение Принципа замещения Лискова (LSP), и в большинстве случаев мы предпочитаем композицию над наследованием. Поддержки к Маркусу Кнаппену Йоханссону, чей первоначальный ответ на это основан.

    Этот код в базовом classе:

      public T As() { 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; } 

    Позволяет:

      derivedObject = baseObect.As() 

    Поскольку он использует reflection, он «дорогой». Используйте соответственно.

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

    Но вы можете назначить экземпляр производного classа переменной типа базового classа.

    Вы можете ввести переменную, которая вводится как базовый class в тип производного classа; однако по необходимости это проведет проверку времени выполнения, чтобы убедиться, что фактический объект имеет правильный тип.

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

    Как говорили все здесь, это невозможно напрямую.

    Метод, который я предпочитаю и довольно чистый, заключается в использовании Map Mapper, например AutoMapper .

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

    Расширение ответа на @ ybo – это невозможно, потому что экземпляр, который у вас есть в базовом classе, на самом деле не является экземпляром производного classа. Он знает только о членах базового classа и ничего не знает о свойствах производного classа.

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

    Нет, это невозможно.

    Рассмотрим сценарий, в котором ACBus является производным classом шины базового classа. ACBus имеет такие функции, как TurnOnAC и TurnOffAC, которые работают в поле ACState. TurnOnAC устанавливает ACState для включения, а TurnOffAC отключает ACState. Если вы попытаетесь использовать функции TurnOnAC и TurnOffAC на шине, это не имеет смысла.

    На самом деле это способ сделать это. Подумайте, как использовать Newtonsoft JSON для десериализации объекта из json. Он (или, по крайней мере, может) игнорирует отсутствующие элементы и заполняет все элементы, о которых он знает.

    Итак, вот как я это сделал. Маленький образец кода будет следовать моим объяснениям.

    1. Создайте экземпляр вашего объекта из базового classа и заполните его соответствующим образом.

    2. Используя class jsonconvert Newtonsoft json, сериализуйте этот объект в строку json.

    3. Теперь создайте объект подclassа, десериализируя строку json, созданную на шаге 2. Это создаст экземпляр вашего подclassа со всеми свойствами базового classа.

    Это работает как шарм! Итак .. когда это полезно? Некоторые люди спрашивали, когда это имеет смысл и предложили изменить схему OP, чтобы учесть тот факт, что вы не можете сделать это с наследованием classа (в .Net).

    В моем случае у меня есть class настроек, который содержит все «базовые» настройки для службы. У конкретных служб больше опций, и они поступают из другой таблицы БД, поэтому эти classы наследуют базовый class. У всех есть разные варианты. Поэтому при извлечении данных для службы гораздо проще FIRST заполнить значения, используя экземпляр базового объекта. Один из способов сделать это с помощью одного запроса БД. Сразу после этого я создаю объект подclassа, используя метод, описанный выше. Затем я делаю второй запрос и заполняю все динамические значения для объекта подclassа.

    Конечный вывод – это производный class со всеми установленными параметрами. Повторение этого для дополнительных новых подclass занимает всего несколько строк кода. Это просто, и он использует очень проверенный и проверенный пакет (Newtonsoft), чтобы заставить магию работать.

    Этот пример кода – vb.Net, но вы можете легко преобразовать его в 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) 
     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"); } } 

    }

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

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

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

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

      public static void CopyProperties(this object destinationObject, object sourceObject, bool overwriteAll = true) { try { if (sourceObject != null) { PropertyInfo[] sourceProps = sourceObject.GetType().GetProperties(); List 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; } } 

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

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

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

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

     public static T Cast(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); 

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

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

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

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

    Когда вы ссылаетесь на библиотеку, используя ссылку Project Reference в Visual Studio, VS показывает squiggles, когда вы используете неявное преобразование, но оно компилируется просто отлично. Если вы просто ссылаетесь на library.dll , нет никаких скриглов.

    Вы можете сделать это с помощью общего.

     public class BaseClass { public int A { get; set; } public int B { get; set; } private T ConvertTo() where T : BaseClass, new() { return new T { A = A, B = B } } public DerivedClass1 ConvertToDerivedClass1() { return ConvertTo(); } public DerivedClass2 ConvertToDerivedClass2() { return ConvertTo(); } } public class DerivedClass1 : BaseClass { public int C { get; set; } } public class DerivedClass2 : BaseClass { public int D { get; set; } } 

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

    1. Вы не дублируете код
    2. Вы не используете reflection (которое медленно)
    3. Все ваши конверсии находятся в одном месте

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

     public static void CopyOnlyEqualProperties(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); } 

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

      private void PopulateDerivedFromBase(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); } } 

    Нет, посмотрите на этот вопрос, который я задал, – Upcasting в .NET с использованием дженериков

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

    Interesting Posts
    Давайте будем гением компьютера.