Копирование содержимого базового класса из производного класса
В настоящее время у меня есть производный класс и базовый класс. Как я могу сделать базовый класс производного класса равным базовому классу, который у меня есть? Работает ли мелкая копия?
class Base
{
private string name;
public string Name { get; set; }
private string address;
public string Address { get; set; }
}
class Derived:Base
{
private string field;
public String field { get; set; }
}
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Base b = new Base();
b.Address = "Iliff";
b.Name = "somename";
Derived d = new Derived();
//How can I make the base class of d equal to b ?
}
}
}
Ответы
Ответ 1
Создайте конструктор копирования для базового класса, при этом вам также потребуется создать без параметров, а также добавив конструктор копирования, который конструктор по умолчанию больше не будет сгенерировать компилятором. Затем в производном классе вызовите конструктор копирования базового класса.
public class Base
{
public int Name { get; set; }
public string Address { get; set; }
public Base()
{ }
public Base(Base toCopy)
{
this.Name = toCopy.Name;
this.Address = toCopy.Address;
}
}
public class Derived : Base
{
public String Field { get; set; }
public Derived(Base toCopy)
: base (toCopy)
{ }
// if desired you'll need a parameterless constructor here too
// so you can instantiate Derived w/o needing an instance of Base
public Derived()
{ }
}
Ответ 2
Другой подход заключается в сопоставлении базового класса с производным классом:
/// <summary>
/// Maps the source object to target object.
/// </summary>
/// <typeparam name="T">Type of target object.</typeparam>
/// <typeparam name="TU">Type of source object.</typeparam>
/// <param name="target">Target object.</param>
/// <param name="source">Source object.</param>
/// <returns>Updated target object.</returns>
public static T Map<T, TU>(this T target, TU source)
{
// get property list of the target object.
// this is a reflection extension which simply gets properties (CanWrite = true).
var tprops = target.GetProperties();
tprops.Where(x=>x.CanWrite == true).ToList().ForEach(prop =>
{
// check whether source object has the the property
var sp = source.GetType().GetProperty(prop);
if (sp != null)
{
// if yes, copy the value to the matching property
var value = sp.GetValue(source, null);
target.GetType().GetProperty(prop).SetValue(target, value, null);
}
});
return target;
}
Пример:
var derivedClass = new DerivedClass();
derivedClass.Map(baseClass);
Ответ 3
Если вы правильно поняли, это будет работать:
class Derived : Base
{
// all the code you had above, plus this:
public Derived(Base toCopy)
{
this.name = toCopy.name;
this.address = toCopy.address;
}
}
Derived d = new Derived(b);
Ответ 4
Вам придется вручную скопировать поля экземпляра Base
в новый экземпляр Derived
.
Обычный способ сделать это - предложить конструктор копирования:
public Derived(Base other)
{
if (other == null) {
throw new ArgumentNullException("other");
}
this.name = other.name;
this.address = other.address;
}
Еще одно примечание о вашем коде:
private string field;
public string Field { get; set; }
Это не имеет большого смысла (то же самое для других свойств).
public string Field { get; set; }
означает, что частное поле будет автоматически создано компилятором. Поле field
никогда не будет использоваться вообще.
Либо просто напишите public string Field { get; set; }
, так как частное поле будет создано автоматически. Или объявите свойство field
таким образом, чтобы ваше личное поле использовалось:
private string field;
public string Field {
get {
return field;
}
set {
field = value;
}
}
Ответ 5
Вы можете всегда использовать Object.MemberwiseClone для его копирования.
http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx
Или реализовать интерфейс IClonable:
http://msdn.microsoft.com/en-us/library/system.icloneable.aspx
Ответ 6
Я придумал довольно хороший образец для решения этой ситуации.
public class Base
{
public int BaseField;
/// <summary>
/// Apply the state of the passed object to this object.
/// </summary>
public virtual void ApplyState(Base obj)
{
BaseField = obj.BaseField;
}
}
public class Derived : Base
{
public int DerivedField;
public override void ApplyState(Base obj)
{
var src = srcObj as Derived;
if (src != null)
{
DerivedField = src.DerivedField;
}
base.ApplyState(srcObj);
}
}
Для любых двух объектов, которые разделяют тип "Base", вы можете применить A к B или B к A.
Ответ 7
Я понимаю, что пару других ответов, возможно, затронули это решение, но я хотел более подробно описать его.
Решение, которое я нашел, состояло в том, чтобы заполнить базовый класс, а затем передать этот базовый класс в конструктор производного класса. Конструктор производного класса заполняет его поля на основе базового класса.
class Base
{
private string name;
public string Name { get; set; }
private string address;
public string Address { get; set; }
}
class Derived:Base
{
Derived(Base toCopy)
{
this.Name = toCopy.Name;
this.Address = toCopy.Address;
}
private string field;
public String field { get; set; }
}
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Base b = new Base();
b.Address = "Iliff";
b.Name = "somename";
//You are now passing the base class into the constructor of the derived class.
Derived d = new Derived(b);
}
}
}
Ответ 8
Я нашел, что EMIT может помочь вам в этом.
Ибо мы будем слишком долго размышлять, но мы можем быстро побывать в Emit.
private static void CloneObjectWithIL<T>(T source, T los)
{
var dynamicMethod = new DynamicMethod("Clone", null, new[] { typeof(T), typeof(T) });
ILGenerator generator = dynamicMethod.GetILGenerator();
foreach (var temp in typeof(T).GetProperties().Where(temp=>temp.CanRead&&temp.CanWrite))
{
generator.Emit(OpCodes.Ldarg_1);// los
generator.Emit(OpCodes.Ldarg_0);// s
generator.Emit(OpCodes.Callvirt,temp.GetMethod);
generator.Emit(OpCodes.Callvirt, temp.SetMethod);
}
generator.Emit(OpCodes.Ret);
var clone = (Action<T, T>) dynamicMethod.CreateDelegate(typeof(Action<T, T>));
clone(source, los);
}
Его можно использовать в качестве этого кода:
public class Base
{
public string BaseField;
}
public class Derived : Base
{
public string DerivedField;
}
Base base = new Base();
//some alother code
Derived derived = new Derived();
CloneObjectWithIL(base, derived);
Более быстрый код - это кеширование.
// ReSharper disable once InconsistentNaming
public static void CloneObjectWithIL<T>(T source, T los)
{
//See http://lindexi.oschina.io/lindexi/post/C-%E4%BD%BF%E7%94%A8Emit%E6%B7%B1%E5%85%8B%E9%9A%86/
if (CachedIl.ContainsKey(typeof(T)))
{
((Action<T, T>) CachedIl[typeof(T)])(source, los);
return;
}
var dynamicMethod = new DynamicMethod("Clone", null, new[] { typeof(T), typeof(T) });
ILGenerator generator = dynamicMethod.GetILGenerator();
foreach (var temp in typeof(T).GetProperties().Where(temp => temp.CanRead && temp.CanWrite))
{
if (temp.GetAccessors(true)[0].IsStatic)
{
continue;
}
generator.Emit(OpCodes.Ldarg_1);// los
generator.Emit(OpCodes.Ldarg_0);// s
generator.Emit(OpCodes.Callvirt, temp.GetMethod);
generator.Emit(OpCodes.Callvirt, temp.SetMethod);
}
generator.Emit(OpCodes.Ret);
var clone = (Action<T, T>) dynamicMethod.CreateDelegate(typeof(Action<T, T>));
CachedIl[typeof(T)] = clone;
clone(source, los);
}
private static Dictionary<Type, Delegate> CachedIl { set; get; } = new Dictionary<Type, Delegate>();
Ответ 9
Просто измените это.
Derived d = (Derived)b;
Кроме того, ваш тип данных имени должен быть строкой, а не int