从基类创建子类的克隆副本
考虑这种情况:
public class Base
{
public int i;
}
public class Sub : Base
{
public void foo() { /* do stuff */}
}
然后我想,给定一个 Base
实例,获取 Sub
的克隆实例(在本例中 i=17),以便我可以调用 < code>foo 在子类中。
Base b = new Base { i=17 };
Sub s = CloneAndUpcast(b);
s.foo();
但是,如何创建CloneAndUpcast
?
我认为应该可以使用反射递归地克隆所有Base
成员和属性。但相当有一些工作。
有人有更好、更简洁的想法吗?
附言。我正在考虑使用它的场景是树状结构中的一组“简单”类(这里没有循环图或类似的),并且所有类都是简单的值持有者。计划是有一个愚蠢的层保存所有值,然后是一组类似的类(子类),这些类实际上包含一些值持有者不应该知道的业务逻辑。一般来说是不好的做法。我认为在这种情况下它是有效的。
Consider this scenario:
public class Base
{
public int i;
}
public class Sub : Base
{
public void foo() { /* do stuff */}
}
And then I want to, given an instance of Base
get an cloned instance of Sub
(with i=17 in this case) so that I can call foo
in the subclass.
Base b = new Base { i=17 };
Sub s = CloneAndUpcast(b);
s.foo();
However, how can I create CloneAndUpcast
?
I am thinking that is should be possible to recursively clone all of Base
-members and properties using reflection. But quite some work.
Anyone with better, neater ideas?
PS. The scenario where I am thinking about using this is a set of "simple" classes in a tree-like structure (no cyclic graphs or similar here) and all the classes are simple value holders. The plan is to have a stupid layer holding all values and then an similar set of classes (the subclasses) that actually contains some business-logic the value-holders shouldn't be aware of. Generally bad practice yes. I think it works in this case.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以使用 AutoMapper 来避免编写复制构造函数的乏味工作。
并且您需要在应用程序启动时运行一次
您可以从 https://github.com/AutoMapper/ 下载 AutoMapper自动映射器
You could use AutoMapper to avoid the tedium of writing the copy constructors.
and you need to run this once when your application starts up
You can download AutoMapper from https://github.com/AutoMapper/AutoMapper
这是一种方法(在多种可能性中),您可以做您所要求的事情。我不确定这是否非常漂亮,并且调试起来可能有点难看,但我认为它有效:
基本上,正如您所建议的,您使用反射来迭代对象的属性(我设置了
i
和j
作为公共属性)并在克隆对象中相应地设置值。关键是使用泛型来告诉 CloneAndUpcast 您正在处理什么类型。一旦你这样做了,事情就非常简单了。希望这有帮助。祝你好运!
Here's one way (out of many possibilities) that you could do something like you're asking. I'm not sure this is very pretty and can be kind of ugly to debug, but I think it works:
Basically, as you suggested, you use reflection to iterate through the object's properties (I set
i
andj
as public properties) and set the values accordingly in the cloned object. The key is using generics to tell CloneAndUpcast what type you're dealing with. Once you do that, it's pretty straightforward.Hope this helps. Good luck!
根据“四人帮”:“优先考虑组合而不是继承”,这是这样做的一个完美理由...
如果我们有一个看起来像这样的超类:
超类可以轻松地装饰 Person 类,添加 Person 中找不到的属性班级。
但是如果超类装饰仅用于 GUI 会发生什么呢?例如,指示“选定”的布尔值。我们仍然能够从列表中的数据库中获取所有人员,但在尝试创建超类并合并数据库结果时遇到了麻烦。
编译器会抱怨,因为 Superclass 对于编译器来说不是一个 Person,它是一个 Superclass。填充 Person 子类的属性的唯一方法是迭代并设置每个属性......就像这样。
确实很乏味。但是有一个更好的方法......不要让超类继承 Person
这给了我们“遏制” 超类现在包含一个 Person 类。
现在我们可以这样做:
这个类的使用者现在必须像这样限定超类/人的属性...
这样做的好处是,将来您可以添加任何您想要的其他容器,并且不会影响任何其他容器。其他容器。您还可以将超类变形为其包含的任何内容。如果每个包含的类都成为接口,那么这就更进一步了。
Per the "Gang of Four" : "Favor composition over inheritance" and this is a perfect reason to do so...
If we have a SuperClass that looks like this:
The SuperClass can easily decorate the Person class adding properties not found in Person class.
But what happens if the Superclass decorations are only for the GUI? For example a bool value indicating "Selected". We are still able to get all Persons from the DB in a List but we run into trouble trying to create the Superclass and merge the DB results.
The compiler complains because Superclass is not a Person to the compiler it's a Superclass. The only way to fill in the properties of the Person subclass is to iterate and set each one... like this.
Pretty tedious indeed. But there's a better way.... Don't make Superclass inherit from Person
This gives us "Containment" The Superclass now contains a Person class.
Now we can do this:
The consumer of this class must now qualify the properties of the Superclass/Person like this...
The beauty of this is that in the future, you can add any other container you want and it will NOT affect any other containers. You can also morph the Superclass to anything it contains. If each of the contained classes become Interfaces, then that's one step futher down the road.
好吧,由于
b
不是Sub
,我们无法将其“克隆”为一个。如果
Base
具有构造函数和公共属性的适当组合,以便让Sub
中的构造函数确保其基类具有与b
相同的状态,那么我们就可以使用它。我想我会绕过整个事情。如果我们关心的是
s
的基数与b
具有相同的状态,并且它没有我们要关心的其他状态(否则我们必须将其传递给CloneAndUpcast
方法),那么我们到底需要s
吗?静态方法可以采用
Base
,我们可以只使用static public void foo(Base bc)
。我们甚至可以将其定义为扩展方法static public void foo(this Base bc)
,然后将调用编码为b.foo()
。CloneAndUpcast()
允许我们做的唯一一件事就是访问受保护的成员。Well, since
b
isn't aSub
, we can't "clone" it as one.If
Base
has an appropriate combination of constructor and public properties to let a constructor inSub
ensure that its base would therefore have the same state asb
, then we could use that.I think I'd by-pass the whole thing though. If all we care about is that
s
have the same state in its base asb
, and it has not other state that we're going to care about (or else we'd have to be passing it through to theCloneAndUpcast
method), then do we needs
at all?A static method could take a
Base
and we could just usestatic public void foo(Base bc)
. We could even define it as an extension methodstatic public void foo(this Base bc)
and then code the call asb.foo()
. The only thing this won't let us do thatCloneAndUpcast()
lets us do is access protected members.克隆是一种不好的做法,您的问题就是其原因(子类克隆)。
一般来说,您应该只使用 copy cotrs 并让子类接受父类作为参数。
public Base(){}
public Base(Base pSource){}
public Sub(){}
public Sub(Base pSource, 其他参数...){}
public Sub(Sub pSource){}
Clone is a bad practice and your question is the reason for that (subclass cloning).
In general, you should just use copy cotrs instead and have the subclass accept a parent as a parameter.
public Base(){}
public Base(Base pSource){}
public Sub(){}
public Sub(Base pSource, other parameters...){}
public Sub(Sub pSource){}