19

我目前有一个派生类和一个基类。如何使派生类的基类等于我拥有的基类?浅拷贝会起作用吗?

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 ?

        }
    }
}
4

10 回答 10

20

为基类创建一个复制构造函数,这样做您还需要创建一个无参数的构造函数,并且通过添加复制构造函数,编译器将不再生成默认构造函数。然后在派生类中调用基类的复制构造函数。

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()
    { }
}
于 2013-01-30T21:27:54.883 回答
11

另一种方法是将基类映射到派生类:

/// <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);
于 2014-03-01T16:29:16.753 回答
10

如果我理解正确,这将起作用:

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);
于 2013-01-30T21:18:36.473 回答
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;
    }
}
于 2013-01-30T21:17:33.670 回答
1

您始终可以使用 Object.MemberwiseClone 来复制它。

http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx

或者实现IClonable接口:http: //msdn.microsoft.com/en-us/library/system.iclonable.aspx

于 2013-01-30T21:23:29.967 回答
1

基于mnyaarar代码,有必要更新获取属性的方式:

public static T Map<T, TU>(this T target, TU source)
{


    // list of writable properties of the destination
    List<PropertyInfo> tprops = typeof(T).GetTypeInfo().DeclaredProperties
                                        .Where(x => x.CanWrite == true).ToList();

    tprops.ForEach(prop =>
            {
                // check whether source object has the the property
                var sp = source.GetType().GetProperty(prop.Name);
                if (sp != null)
                {
                    // if yes, copy the value to the matching property
                    var value = sp.GetValue(source, null);
                    target.GetType().GetProperty(prop.Name).SetValue(target, value, null);
                }
            });
}
于 2020-03-19T11:22:05.017 回答
1

我想出了一个很好的模式来处理这种情况。

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。

于 2016-02-24T01:16:22.977 回答
0

我发现 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>();
于 2017-10-05T07:45:39.040 回答
0

我意识到其他几个答案可能已经触及这个解决方案,但我想更完整地说明它。

我找到的解决方案是填充基类,然后将该基类传递给派生类的构造函数。派生类的构造函数根据基类填充其字段。

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


        }
    }
}
于 2016-07-06T17:04:53.290 回答
-6

只要改变这个。

Derived d = (Derived)b;

此外,您的姓名数据类型应该是字符串,而不是 int

于 2013-01-30T21:16:26.310 回答