从父对象继承值来扩展对象

3
假设我有一个类:
public class Parent
{
    public string Name { get; set; }
    public string City { get; set; }
}

在某个函数中,我得到了一个名为Parent类型的对象列表,接下来我想要通过添加一些值来扩展这些对象的新字段,因此我声明了一个扩展类,如下所示:

public class Child : Parent
{
    public Child(Parent parent)
    {
        Name = parent.Name;
        City = parent.City;
    }
    public int Age { get; set; }
}

并为每个扩展对象调用构造函数。有没有更好的方法来做到这一点?如果 Parent 中有多个属性怎么办?也许有一种更优雅的方式来实现这一点?


1
你为什么要在两个类之间传输数据,而不是直接首先进入“Child”呢? - Joel Etherton
为什么Child要继承Parent?孩子真的也是父母吗?(显然这是可能的,但在这种情况下感觉不太对)。Child应该有一个Parent属性吗? - Dave Zych
1
这个问题的动机是我得到一个带有数据的对象列表,并且想显示这些数据,但是需要添加一些额外的字段,而不需要修改基类。 - Steve Macculan
@SteveMacculan:不需要触及基类或实例吗?我的问题是关于用法的。为什么要加载到“Parent”中,然后再转移到“Child”中?您是否在“Parent”中执行与“Child”不能(或不应)适应的单独操作?我的问题显然是无意义的,因为您已经接受了一个答案,但这有助于选择正确的设计模式。 - Joel Etherton
4个回答

4

我觉得你可能在寻找复制构造器模式。每个级别都定义了一个protected构造函数,用于复制相关属性:

public class Parent
{
    public string Name { get; set; }
    public string City { get; set; }

    //normal constructor
    public Parent()
    {

    }

    protected Parent(Parent copy)
    {
        this.Name = copy.Name;
        this.City = copy.City;
    }
}

Child将从Parent继承,并通过复制构造函数传递下去,然后根据需要附加其新值:

public class Child : Parent
{
    public string NewInfo { get; set; }

    public Child(Parent copy)
        : base(copy)
    {

    }
}

使用示例可能如下:

Parent parent = new Parent() { Name = "Name", City = "StackOverflow"};

Child child = new Child(parent) { NewInfo = "Something new!" };

Console.WriteLine(child.Name); //Name
Console.WriteLine(child.City); //StackOverflow
Console.WriteLine(child.NewInfo); //Something new!

这样做的好处是,您可以拥有多个继承级别,每个级别都管理自己的属性。
编辑:根据您最近的评论:
引起这个问题的动机是我正在接收一个带有数据的对象列表,并且想显示这些数据但又想加上一些额外的字段,而不影响基础类。
也许更好的方法是包装基础类:
public class Child
{
    private readonly Parent WrappedParent;

    public string NewInfo { get; set; }

    public string Name 
    { 
        get { return WrappedParent.Name; }
        set { WrappedParent.Name = value; }
    }

    public string City 
    { 
        get { return WrappedParent.City; }
        set { WrappedParent.City = value; }
    }

    public Child(Parent wrappedParent)
    {
        this.WrappedParent = wrappedParent; 
    }
}

缺点是您必须重新声明每个属性,并且不再继承(不能被视为)"Parent",但是您肯定不再“触及”基类了。如果这对您更好,可以将“Parent”属性移动到IParent接口中,但是这样做又会“触及”基类,因为您需要将IParent接口声明添加到其类定义中。


1
不确定我是否理解正确,但这可能是一种更标准的解决方案。
public class Parent
{
    public Parent(string name, string city)
    {
       Name = name;
       City = city;
    }

    public string Name { get; set; }
    public string City { get; set; }
}

public class Child : Parent
{
    public Child(string name, string city, int age) : base(name, city)
    {
       Age = age;
    }
    public int Age { get; set; }
} 

这个方法是可行的,适用于属性相对较少的对象,但当属性数量众多时会变得繁琐。 - Joel Etherton
这并没有回答问题,只是展示了基本的类扩展。原始问题要求新创建的Child对象反映现有Parent对象的当前字段和属性。就像接受的答案一样。 - radfast

0

你可以做到这个

public class Parent
{
    public string Name { get; set; }
    public string City { get; set; }

    public Parent(string name, string city)
    {
        this.Name = name;
        this.City = city;
    }

    public Parent():this(string.Empty, string.Empty)
    {
    }
}

public class Child : Parent
{
    public Child(Parent parent, int age):base(parent.Name, parent.City)
    {
        this.Age = age;
    }

    public int Age { get; set; }
}

这不是复制粘贴,我们几乎同时发布的。 - Hossein Narimani Rad

0
在最近的 Visual Studio 版本中(VS Community Edition 2019),我能够输入以下内容:
internal class Child : IParent
{
    private IParent parent;
    public ChildField childField;

    public Child(IParent parent, ChildField newChildField)
    {
        this.parent = parent;
        this.childField = newChildField;
    }
}

我接着鼠标悬停在 IParent 上(因为它显示了一个错误信息,说明没有完全实现),按下 Ctrl . 来解决这个错误,其中一个选项是 "通过父级实现接口"。点击该选项,VS会为你打出所有的属性和方法,并将其包装在基类中。简单、正确而且很棒。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接