Копирование содержимого базового класса из производного класса

В настоящее время у меня есть производный класс и базовый класс. Как я могу сделать базовый класс производного класса равным базовому классу, который у меня есть? Работает ли мелкая копия?

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

Ответ 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