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
Copying the contents of a base class from a derived class
提问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 Base
instance to the new Derived
instance.
您必须手动将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 field
field 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 Field
property 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);
}
});
}