从基类方法克隆派生类
我有一个抽象基类Base
,它有一些共同的属性,以及许多派生的实现不同逻辑但很少有其他字段。
public abstract Base { protected int field1; protected int field2; .... protected Base() { ... } }
有时我需要克隆派生类。 所以我的猜测是,只需在我的基类中创建一个虚拟Clone
方法,并且只在具有其他字段的派生类中覆盖它,但当然我的Base
类不再是抽象的(这不是问题,因为它只有protected
构造函数)。
public Base { protected int field1; protected int field2; .... protected Base() { ... } public virtual Base Clone() { return new Base(); } } public A : Base { } public B : Base { }
-
问题是,因为我无法知道我的Base类中的派生类的类型,即使我在派生类上调用它,这也不会导致有一个
Base
类实例吗? (a.Clone();
)(实际上在测试之后这是发生了什么,但也许我的测试没有很好地设计,这就是为什么我对它有疑问) -
是否有一种很好的方法(模式)来实现一个基本的
Clone
方法,它可以按照我的预期工作,或者我必须在每个派生类中编写相同的代码(我真的想避免这种情况……)
谢谢你的帮助
只需覆盖Clone
并为CreateInstance
提供另一种方法,然后执行您的操作。
这样你就可以只有Base
类来避免generics。
public Base { protected int field1; protected int field2; .... protected Base() { ... } public virtual Base Clone() { var bc = CreateInstanceForClone(); bc.field1 = 1; bc.field2 = 2; return bc; } protected virtual Base CreateInstanceForClone() { return new Base(); } } public A : Base { protected int fieldInA; public virtual Base Clone() { var a = (A)base.Clone(); a.fieldInA =5; return a; } protected virtual Base CreateInstanceForClone() { return new A(); } }
您可以将复制构造函数添加到基类:
public abstract Base { protected int field1; protected int field2; protected Base() { ... } protected Base(Base copyThis) : this() { this.field1 = copyThis.field1; this.field2 = copyThis.field2; } public abstract Base Clone(); } public Child1 : Base { protected int field3; public Child1 () : base() { ... } protected Child1 (Child1 copyThis) : base(copyThis) { this.field3 = copyThis.field3; } public override Base Clone() { return new Child1(this); } } public Child2 : Base { public Child2 () : base() { ... } protected Child (Child copyThis) : base(copyThis) { } public override Base Clone() { return new Child2(this); } } public Child3 : Base { protected int field4; public Child3 () : base() { ... } protected Child3 (Child3 copyThis) : base(copyThis) { this.field4 = copyThis.field4; } public override Base Clone() { var result = new Child1(this); result.field1 = result.field2 - result.field1; } }
你可以这样做:
public class Base where T: Base , new() { public virtual T Clone() { T copy = new T(); copy.Id = this.Id; return copy; } public string Id { get; set; } } public class A : Base { public override A Clone() { A copy = base.Clone(); copy.Name = this.Name; return copy; } public string Name { get; set; } } private void Test() { A a = new A(); A aCopy = a.Clone(); }
但我怀疑它会带来一些有用的东西。 我将创建另一个例子..
我有另一个想法使用Activator类:
public class Base { public virtual object Clone() { Base copy = (Base)Activator.CreateInstance(this.GetType()); copy.Id = this.Id; return copy; } public string Id { get; set; } } public class A : Base { public override object Clone() { A copy = (A)base.Clone(); copy.Name = this.Name; return copy; } public string Name { get; set; } } A a = new A(); A aCopy = (A)a.Clone();
但我会选择亚历山大·西蒙诺夫的回答。
我做了类似Alexander Simonov的事情,但也许更简单。 这个想法是(正如我在评论中所说的Clone()
在基类中只有一个 Clone()
并将所有工作留给虚拟CloneImpl()
,每个类根据需要定义,依赖于基类的CloneImpl()
类。
正确类型的创建留给C#的MemberwiseClone()
,它将对正在调用的对象执行任何操作。 这也消除了在任何类中都需要默认构造函数(没有调用过)。
using System; namespace CloneImplDemo { // dummy data class class DeepDataT : ICloneable { public int i; public object Clone() { return MemberwiseClone(); } } class Base: ICloneable { protected virtual Base CloneImpl() { // Neat: Creates the type of whatever object is calling. // Also obviates the need for default constructors // (Neither Derived1T nor Derived2T have one.) return (Base)MemberwiseClone(); } public object Clone() { // Calls whatever CloneImpl the // actual calling type implements. return CloneImpl(); } } // Note: No Clone() re-implementation class Derived1T : Base { public Derived1T(int i) { der1Data.i = i; } public DeepDataT der1Data = new DeepDataT(); protected override Base CloneImpl() { Derived1T cloned = (Derived1T)base.CloneImpl(); cloned.der1Data = (DeepDataT)der1Data.Clone(); return cloned; } } // Note: No Clone() re-implementation. class Derived2T : Derived1T { public Derived2T(int i1, int i2) : base(i1) { der2Data.i = i2; } public string txt = string.Empty; // copied by MemberwiseClone() public DeepDataT der2Data = new DeepDataT(); protected override Base CloneImpl() { Derived2T cloned = (Derived2T)base.CloneImpl(); // base members have been taken care of in the base impl. // we only add our own stuff. cloned.der2Data = (DeepDataT)der2Data.Clone(); return cloned; } } class Program { static void Main(string[] args) { var obj1 = new Derived2T(1,2); obj1.txt = "this is obj1"; var obj2 = (Derived2T)obj1.Clone(); obj2.der1Data.i++; obj2.der2Data.i++; // changes value. obj2.txt = "this is a deep copy"; // replaces reference. // the values for i should differ because // we performed a deep copy of the DeepDataT members. Console.WriteLine("obj1 txt, i1, i2: " + obj1.txt + ", " + obj1.der1Data.i + ", " + obj1.der2Data.i); Console.WriteLine("obj2 txt, i1, i2: " + obj2.txt + ", " + obj2.der1Data.i + ", " + obj2.der2Data.i); } } }
输出:
obj1 txt, i1, i2: this is obj1, 1, 2 obj2 txt, i1, i2: this is a deep copy, 2, 3
如果性能对您的情况不重要,您可以通过创建一个通用克隆方法来简化代码,如果属性相同,可以克隆任何内容:
Base base = new Base(){...}; Derived derived = XmlClone.CloneToDerived (base); public static class XmlClone { public static D CloneToDerived(T pattern) where T : class { using (var ms = new MemoryStream()) { using (XmlWriter writer = XmlWriter.Create(ms)) { Type typePattern = typeof(T); Type typeTarget = typeof(D); XmlSerializer xmlSerializerIn = new XmlSerializer(typePattern); xmlSerializerIn.Serialize(writer, pattern); ms.Position = 0; XmlSerializer xmlSerializerOut = new XmlSerializer(typeTarget, new XmlRootAttribute(typePattern.Name)); D copy = (D)xmlSerializerOut.Deserialize(ms); return copy; } } } }
在尝试解决这个问题的同时找到了这个问题,在使用LINQPad时有一些乐趣。 概念certificate:
上述就是C#学习教程:从基类方法克隆派生类分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
void Main() { Person p = new Person() { Name = "Person Name", Dates = new List() { DateTime.Now } }; new Manager() { Subordinates = 5 }.Apply(p).Dump(); } public static class Ext { public static TResult Apply(this TResult result, TSource source) where TResult: TSource { var props = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var p in props) { p.SetValue(result, p.GetValue(source)); } return result; } } class Person { public string Name { get; set; } public List Dates { get; set; } } class Manager : Person { public int Subordinates { get; set; } }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/959397.html