考虑这种情况:
public class Base
{
public int i;
}
public class Sub : Base
{
public void foo() { /* do stuff */}
}
Run Code Online (Sandbox Code Playgroud)
然后我想,给一个Base获得克隆实例的实例Sub(在这种情况下i = 17),这样我就可以foo在子类中调用.
Base b = new Base { i=17 };
Sub s = CloneAndUpcast(b);
s.foo();
Run Code Online (Sandbox Code Playgroud)
但是,我该如何创作CloneAndUpcast?
我认为应该可以Base使用反射递归克隆所有 - 成员和属性.但相当一些工作.
谁有更好,更整洁的想法?
PS.我正在考虑使用它的场景是一组树状结构中的"简单"类(这里没有循环图或类似的),所有类都是简单的值持有者.计划是有一个包含所有值的愚蠢层,然后是一组类似的类(子类),它们实际上包含了值持有者不应该知道的一些业务逻辑.一般不好的做法是的.我认为它适用于这种情况.
小智 13
您可以使用AutoMapper来避免编写复制构造函数的繁琐.
public class MyClass : MyBase
{
public MyClass(MyBase source)
{
Mapper.Map(source, this);
}
}
Run Code Online (Sandbox Code Playgroud)
并且您需要在应用程序启动时运行一次
Mapper.CreateMap<MyBase, MyClass>();
Run Code Online (Sandbox Code Playgroud)
您可以从https://github.com/AutoMapper/AutoMapper下载AutoMapper
这是一种方式(在许多可能性中),你可以做你喜欢的事情.我不确定这是非常漂亮的并且可能有点难以调试,但我认为它有效:
class BaseClass
{
public int i { get; set; }
public BaseClass Clone(BaseClass b)
{
BaseClass clone = new BaseClass();
clone.i = b.i;
return clone;
}
}
class SubClass : BaseClass
{
public int j { get; set; }
public void foo() { Console.WriteLine("in SubClass with value of i = {0}", i.ToString()); }
}
class Program
{
static void Main(string[] args)
{
BaseClass b1 = new BaseClass() { i = 17 };
BaseClass b2 = new BaseClass() { i = 35 };
SubClass sub1 = CloneAndUpcast<SubClass>(b1);
SubClass sub2 = CloneAndUpcast<SubClass>(b2);
sub1.foo();
sub2.foo();
}
static T CloneAndUpcast<T>(BaseClass b) where T : BaseClass, new()
{
T clone = new T();
var members = b.GetType().GetMembers(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < members.Length; i++)
{
if (members[i].MemberType== MemberTypes.Property)
{
clone
.GetType()
.GetProperty(members[i].Name)
.SetValue(clone, b.GetType().GetProperty(members[i].Name).GetValue(b, null), null);
}
}
return clone;
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,正如您所建议的那样,您使用反射来遍历对象的属性(我设置i和j作为公共属性)并在克隆对象中相应地设置值.关键是使用泛型来告诉CloneAndUpcast你正在处理什么类型.一旦你这样做,它就非常简单.
希望这可以帮助.祝好运!
根据“四人帮”:“优先考虑组合而不是继承”,这是这样做的完美理由......
如果我们有一个看起来像这样的超类:
public class SuperClass : Person
Run Code Online (Sandbox Code Playgroud)
SuperClass 可以轻松地装饰 Person 类,添加 Person 类中没有的属性。但是如果超类装饰仅用于 GUI 会发生什么?例如,指示“选定”的布尔值。我们仍然能够从列表中的数据库中获取所有人员,但在尝试创建超类并合并数据库结果时遇到了麻烦。
foreach( var person in myPersonList){
var sc = new SuperClass();
sc.Selected = false;
sc=person;
}
Run Code Online (Sandbox Code Playgroud)
编译器会抱怨,因为 Superclass 对于编译器来说不是一个 Person,它是一个 Superclass。填充 Person 子类的属性的唯一方法是迭代并设置每个属性......就像这样。
SuperClass.Name = Person.Name;
SuperClass.Id = Person.ID;
Run Code Online (Sandbox Code Playgroud)
确实很乏味。但有一个更好的方法......不要让超类继承自 Person
public class SuperClass{
public Person ThisPerson {get;set;}
public bool Selected {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
这给了我们“遏制”超类现在包含一个 Person 类。
现在我们可以这样做:
foreach(var person in MyPersonList){
var sc = new Superclass();
sc.Selected = false;
sc.Person = person;
}
Run Code Online (Sandbox Code Playgroud)
这个类的消费者现在必须像这样限定超类/人的属性......
forach(var sc in MySuperClassList){
var selected = sc.Selected;
var name = sc.Person.Name;
}
Run Code Online (Sandbox Code Playgroud)
这样做的好处是,将来您可以添加任何您想要的其他容器,并且不会影响任何其他容器。您还可以将超类变形为其包含的任何内容。如果每个包含的类都成为接口,那么这就更进一步了。
| 归档时间: |
|
| 查看次数: |
6649 次 |
| 最近记录: |