首页 新闻 会员 周边

一个很简单的基类赋值的疑惑

0
悬赏园豆:30 [已解决问题] 解决于 2009-11-09 16:31

大家先看一段简单的代码,我想实现的是基类简单赋值,而不是考属性一个个的来赋值。

 public class A
{
public int p1 {
get;
set;
}
}

public class B : A
{
public B(A data) {
base = data;
}
}
注意到base=data 这里的时候是错误的,编译也不通过,请问大家这是为什么呢?base的具体含义究竟是什么。请问大家有什么解决的办法没(如果是base.p1 = data.p1就算了,属性太多的时候就繁琐了)。

 

 

问题补充: 我后来自己写了两个方法(反射和序列化克隆) 1反射: public static W Autovalueofbase<T , W>(T data) where T : new() where W : T,new() { W w = new W(); foreach (var p in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty)) { p.SetValue(w , p.GetValue(data , null) , null); } return w; } 2序列化克隆: public static void SerializeClone<T>(this T data , T target) where T : class , new() { using (System.IO.MemoryStream stream = new System.IO.MemoryStream(1000)) { BinaryFormatter bf = new BinaryFormatter(null , new StreamingContext(StreamingContextStates.Clone)); bf.Serialize(stream , data); stream.Seek(0 , System.IO.SeekOrigin.Begin); target = (T)bf.Deserialize(stream); stream.Close(); } } 第一个方案是可行的,但是因性能上的考虑尽量不用,而第二种好像不能实现我的目的
Joyaspx的主页 Joyaspx | 初学一级 | 园豆:170
提问于:2009-11-09 10:10
< >
分享
最佳答案
0

base是基类的引用,当实例化B的时候,B的引用实际上和base是一样的,

而一个类的实例是无法在自身内部修改自己的引用地址的

一般的解决方法是实现Clone,通过Clone拷贝值.当然,实现Clone实际也是

要写类似 base.p1 = data.p1 这样的语句的.

 

如果基类A是相对稳定的,那么让A实现Clone,写一次属性赋值,也不是很难看的

解决方案.

如果实际中,你是有很多这样的基类A,那么用反射来实现Clone的功能是可以大大

减少代码量,其代价则是性能.

如果你的基类A支持序列化,使用序列化来实现Clone功能,也是可以的.

最后一种方式,是使用序列化,准确的说,是封送(C++里一直说的是序列化,在.NET里为了区别,使用了COM中相关的称谓),通过往指定地址空间写入指定大小的数据,达到更改类实例字段值的目的.

 

//测试类
[StructLayout(LayoutKind.Sequential)]
public class TestClassBase
{
public string Text { get; set; }
public int Order { get; set; }
}

[StructLayout(LayoutKind.Sequential)]
public class TestClass : TestClassBase
{
public TestClass(TestClassBase data)
{
if (data == null)
return;

int size = Marshal.SizeOf(data);
if (size == 0)
return;

IntPtr ptr
= IntPtr.Zero;

try
{
ptr
= Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(data, ptr,
true);
Marshal.PtrToStructure(ptr,
this);
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.FreeHGlobal(ptr);
}
}
}

//测试方法
TestClassBase obj1 = new TestClassBase { Order=2, Text = "基类"};
TestClass obj
= new TestClass(obj1);
            
收获园豆:25
Launcher | 高人七级 |园豆:45045 | 2009-11-09 11:14
事实上我后来也做了两种方案来实现我想要的功能,一种是反射来赋值,一种是通过序列化来克隆。第一种实现是没问题,但是就像你说的有性能上的考虑尽量不用,第二种通过序列化很难找到赋值的对象,你能给我实例吗?谢谢
Joyaspx | 园豆:170 (初学一级) | 2009-11-09 13:28
你的方法我已经测试通过,对于封送的概念我还是比较陌生,不知道性能是否有所损失还有待学习。 很是感谢你提供的这第三种方法,也是我为涉及的一个领域。
Joyaspx | 园豆:170 (初学一级) | 2009-11-09 16:31
其他回答(2)
0

兄弟 你要改变它什么,既然是子类,已经是完全继承了,你为什么还要给父类赋值呢?不好也不规范

收获园豆:1
James.Ying | 园豆:1472 (小虾三级) | 2009-11-09 11:24
子类初始化的时候事实上就初始化了父类的值,给父类赋值为了减少代码量
支持(0) 反对(0) Joyaspx | 园豆:170 (初学一级) | 2009-11-09 13:24
0

先回答楼主的问题,再评论楼主的做法。

1、注意到base=data 这里的时候是错误的,编译也不通过,请问大家这是为什么呢?base的具体含义究竟是什么?

因为base代表的是基类,data是实例,把实例覆给类就好比B=new B()一样,显然是不行的。

2、请问大家有什么解决的办法没?

就用你说算了的方法。

不知道楼主有没有注意到,public B(A data)中data产生的时候你是要对它进行一次属性赋值的,也就是说对A的属性一个个赋值你是无法避免的。

收获园豆:4
dege301 | 园豆:2825 (老鸟四级) | 2009-11-09 12:55
我最开始的想法是:base也是一个对象(注意这里是对象不是类),既然是对象就有引用地址和存放空间,那么就可以赋值,所以在我看来base就是一个对象,后来发现我的认识是错误的,base关键字所代表的含义还是很特殊的,它可以用来访问积累成员却不能代表整个基类。 这里出现不能赋值的问题我想是不是所谓的边界问题,还值得深入探讨
支持(0) 反对(0) Joyaspx | 园豆:170 (初学一级) | 2009-11-09 13:45
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册