C# 如何强制派生类填充基类中定义的列表?

C# 如何强制派生类填充基类中定义的列表?,c#,polymorphism,C#,Polymorphism,这是与C相关的,但实际上这个问题相当普遍 假设我有一个基类 abstract class Base { protected List<string> MyList = new List<string>(); protected abstract void FillMyList(); } class Derived : Base { protected void FillMyList() { MyList.Add("test");

这是与C相关的,但实际上这个问题相当普遍

假设我有一个基类

abstract class Base {
    protected List<string> MyList = new List<string>();
    protected abstract void FillMyList();
}

class Derived : Base {
    protected void FillMyList() {
        MyList.Add("test");
        MyList.Add("test2");
    }
}
这样就可以了,派生类将填充基类中定义的MyList

然而,除了抽象方法名FillMyList(这意味着您实际上必须填写MyList)之外,对于这个方法的含义没有任何线索

是否有更好的方法来强制执行或更好地强烈建议您在从Base继承时必须填写MyList? 可能将FillMyList声明为:

protected abstract void FillMyList(List<string> listToFill);

你有什么建议?

如何定义填充?如果您只是想添加一些元素,那么您可以简单地添加另一个抽象方法来检索要添加的项,然后在基类中实现FillMyList以将这些项添加到列表中。例如:

abstract class Base
{
    protected List<string> MyList = new List<string>();

    protected abstract IEnumerable<string> GetItems();

    protected void FillMyList()
    {
        MyList.AddRange(GetItems());
    }
}

class Derived : Base
{
    protected override IEnumerable<string> GetItems()
    {
        yield return "test";
        yield return "test2";
    }
}
完成此操作后,根据您的要求,可能适合将FillMyList更改为private。还要注意,派生中的方法必须标记为重写


当然,实现这一目标有很多不同的方法。例如,您可以按照Nagg的建议,简单地将MyList属性本身抽象化。

如何定义填充?如果您只是想添加一些元素,那么您可以简单地添加另一个抽象方法来检索要添加的项,然后在基类中实现FillMyList以将这些项添加到列表中。例如:

abstract class Base
{
    protected List<string> MyList = new List<string>();

    protected abstract IEnumerable<string> GetItems();

    protected void FillMyList()
    {
        MyList.AddRange(GetItems());
    }
}

class Derived : Base
{
    protected override IEnumerable<string> GetItems()
    {
        yield return "test";
        yield return "test2";
    }
}
完成此操作后,根据您的要求,可能适合将FillMyList更改为private。还要注意,派生中的方法必须标记为重写


当然,实现这一目标有很多不同的方法。例如,您可以简单地将MyList属性本身抽象化,正如Nagg所建议的那样。

您可以使用getter将MyList转换为抽象属性,getter必须实现

public abstract class Base
{
    public abstract List<int> List { get; }
}

public class Derived : Base
{
    #region Overrides of Base

    public override List<int> List
    {
        get { return new List<int> {1, 2, 3}; }
    }

    #endregion
}

可以使用getter将MyList转换为抽象属性,派生属性必须实现

public abstract class Base
{
    public abstract List<int> List { get; }
}

public class Derived : Base
{
    #region Overrides of Base

    public override List<int> List
    {
        get { return new List<int> {1, 2, 3}; }
    }

    #endregion
}

我认为,如果有什么地方不对劲,例如,列表没有正确填写,那么当你试图使用它时,你应该抛出一个异常。这样,您将始终获得正确的数据。即使类是抽象的,用户也可以将其实现为空方法,因此这不是更好的方法。

我认为,如果出现问题,即列表填写不正确,则在尝试使用它时应该抛出异常。这样,您将始终获得正确的数据。即使类是抽象的,用户也可以将其实现为空方法,因此这并不是更好的方法。

您可以这样做:

abstract class Base {
     protected List<string> TheList
     {
         get {
             Debug.Assert(MyList.Count != 0);
             return MyList;
         }
         set {
             Debug.Assert(value.Count != 0);
             MyList = value;
         }
     }
     private List<string> MyList = new List<string>();
}

您的派生对象只能通过执行检查的属性访问MyList。

您可以执行以下操作:

abstract class Base {
     protected List<string> TheList
     {
         get {
             Debug.Assert(MyList.Count != 0);
             return MyList;
         }
         set {
             Debug.Assert(value.Count != 0);
             MyList = value;
         }
     }
     private List<string> MyList = new List<string>();
}

您的派生对象只能通过将执行检查的属性访问MyList。

抽象方法和属性都具有相同的效果,即必须在Nagg中实现它,这就实现了。谢谢@saurabh:是的,但这会迫使派生函数执行某些操作,并实际返回列表,即使列表为空。抽象方法和属性都会产生相同的效果,即必须在Nagg中实现它,这就完成了。谢谢@saurabh:是的,但这会迫使派生函数做一些事情,并实际返回列表,即使列表为空。谢谢Will,你的答案也很有趣:谢谢Will,你的答案也很有趣: