C# 从派生类复制基类的内容

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14613919/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 12:25:54  来源:igfitidea点击:

Copying the contents of a base class from a derived class

c#

提问by Casper_2211

I currently have a derived class and a base class. How can I make the base class of the derived class equal to a base class that I have? Will a shallow copy work?

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

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 ?

        }
    }
}

回答by Unknwon

Just change this.

只要改变这个。

Derived d = (Derived)b;

Also, your name data type should be string, not int

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

回答by O. R. Mapper

You will have to manually copy the fields of the Baseinstance to the new Derivedinstance.

您必须手动将Base实例的字段复制到新Derived实例。

A common way of doing this is by offering a copy constructor:

一种常见的方法是提供一个复制构造函数:

public Derived(Base other)
{
    if (other == null) {
        throw new ArgumentNullException("other");
    }

    this.name = other.name;
    this.address = other.address;
}


One more note about your code:

关于您的代码的另一个注意事项:

private string field; 
public string Field { get; set; }

This does not make much sense (same for the other properties).

这没有多大意义(其他属性也是如此)。

public string Field { get; set; }means that a private field will automatically be created by the compiler. Your fieldfield will never be used at all.

public string Field { get; set; }意味着编译器会自动创建一个私有字段。你的field领域将永远不会被使用。

Either just write public string Field { get; set; }, as the private field will be created automatically. Or declare the Fieldproperty in a way so that your private field will be used:

要么只写public string Field { get; set; },因为私有字段将自动创建。或者Field以某种方式声明属性,以便使用您的私有字段:

private string field;

public string Field {
    get {
        return field;
    }
    set {
        field = value;
    }
}

回答by Ben

If I understand you correctly, this will work:

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

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

回答by Bauss

You can always use Object.MemberwiseClone to copy it.

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

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

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

Or implement the IClonable interface: http://msdn.microsoft.com/en-us/library/system.icloneable.aspx

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

回答by JG in SD

Create a copy constructor for the base class, in doing so you'll also need to create a parameterless one as well as by adding the copy constructor the default constructor will no longer be generated by the compiler. Then in the derived class call the base class's copy constructor.

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

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()
    { }
}

回答by mnyarar

Another approach would be to map the base class to derived class:

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

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

Example:

例子:

var derivedClass = new DerivedClass();
derivedClass.Map(baseClass);

回答by James

I came up with a pretty good pattern for dealing with this situation.

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

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

Given any two objects that share type 'Base', you can apply A to B or B to A.

给定任何两个共享类型“Base”的对象,您可以将 A 应用于 B 或 B 应用于 A。

回答by CWeaver

I realize that a couple of other answers may have touched on this solution, but I wanted to spell it out more completely.

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

The solution I found was to populate the base class, then pass that base class into the constructor of the derived class. The constructor of the derived class populates its fields based on the base class.

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

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


        }
    }
}

回答by lindexi

I found EMIT may help you for this.

我发现 EMIT 可以为您提供帮助。

For we will spend too long in reflection but we can be fast in 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);
    }

It can be use as this code:

它可以用作此代码:

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

The more fast code is to cache it.

更快的代码是缓存它。

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

回答by mainmind83

Based on mnyararcode, it would be necessary update the way to obtain the properties:

根据mnyarar代码,有必要更新获取属性的方式:

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