【问题标题】:Can I pass arguments to a base constructor from a derived class's default constructor?我可以将参数从派生类的默认构造函数传递给基构造函数吗?
【发布时间】:2013-09-14 04:35:17
【问题描述】:

假设我有一个抽象基类 Deck:

public abstract class Deck
{
   public List<Card> cards;

   public Deck(string[] values, string[] suits)
   {...}

   ...
}

还有一个派生类 EuchreDeck:

public class EuchreDeck : Deck
{
   string[] values = new string[] { "9", "10", "J", "Q", "K", "A" };
   string[] suits = new string[] { "clubs", "spades", "hearts", "diamonds" };

   public EuchreDeck() : base(values, suits) // Error.
   {}

   ...
}

我希望能够实例化EuchreDeck 并将两个字符串数组传递给基类,即var gameDeck = new EuchreDeck();

目前我收到错误消息:“非静态字段、方法或属性 EuchreDeck.values 需要对象引用。”

这可能吗,还是调用派生默认构造函数总是调用基默认构造函数?

【问题讨论】:

    标签: c# constructor abstract-class derived-class


    【解决方案1】:

    是的,如果你制作数组static,你可以这样做:

    public class EuchreDeck : Deck
    {
       private static readonly string[] values = new string[] { "9", "10", "J", "Q", "K", "A" };
       private static readonly string[] suits = new string[] { "clubs", "spades", "hearts", "diamonds" };
    
       public EuchreDeck() : base(values, suits)
       {
    
       }
    }
    

    您不能像对实例级成员一样使用它的原因是这样做是不合法的。这来自C# specification 10.10.1 Constructor Initializers,它指出:

    实例构造函数初始化程序无法访问正在被调用的实例 创建。因此,在 构造函数初始化器的参数表达式,因为它是 引用任何参数表达式的编译时错误 通过简单名称的实例成员。

    通过将数组切换为static,它们不再通过实例访问,而是通过EuchreDecktype


    也就是说,我可能会建议您对设计稍作调整。也许使用工厂为您而不是它们的构造器创建这些专门的套牌。

    作为一个示例,也许重构如下:

    将你的基础Deck 改为只拿一组卡片:

    public abstract class Deck
    {
        public List<Card> Cards;
        protected Deck(IEnumerable<Card> cards)
        {
            this.Cards = new List<Card>(cards);
        }
    }
    

    然后像这样进行出厂设置:

    public class EuchreDeck : Deck
    {
        private EuchreDeck(IEnumerable<Card> cards) : base(cards)
        {
    
        }
    
        public class Factory : DeckFactory
        { 
            private static readonly string[] Values = new string[] { "9", "10", "J", "Q", "K", "A" };
            private static readonly string[] Suits = new string[] { "clubs", "spades", "hearts", "diamonds" };
    
            public static EuchreDeck Create()
            {
                var cards = CreateCards(Values, Suits);
                return new EuchreDeck(cards);
            }
        }
    }
    

    实例化/用法:

    EuchreDeck.Factory.Create();
    

    您可以尝试使用工厂用法。我只是将它嵌套在类中,因此您无法创建带有无效卡片集的EuchreDeck。您的 DeckFactory 基础将具有您的转换方法(看起来您当前在 Deck 构造函数中具有)

    除此之外,我不确定您是否特别需要EuchreDeck;我假设您还有其他与之相关的方法?如果没有,您可能完全放弃该课程,而让工厂创建一个带有所需卡片的Deck

    【讨论】:

    • 很好的答案,您解决了我的具体问题并提供了一些设计级别的建议。谢谢!
    【解决方案2】:

    你必须有一个变量贴花的地方:

    public EuchreDeck() : base(values, suits) // Error.
    {}
    

    valuessuits 在哪里声明?

    你必须定义它们static,比如:

    static readonly string[] values = new string[] { "9", "10", "J", "Q", "K", "A" };
    static readonly string[] suits = new string[] 
                  { "clubs", "spades", "hearts", "diamonds" }; 
    

    问题是base(..) 只能访问 ctor 范围内的值可见。因此您不能传递 instance 变量,因为在该级别上无法访问实例,但您可以传递调用类的 ctor 参数静态成员 .

    【讨论】:

    • 它们在派生类中声明。
    • @Zach:好的,但这有什么问题?
    • 问题是我没有像你和其他人建议的那样将它们声明为static。这修复了编译错误,我现在正在探索使用工厂方法,正如 Chris 建议的 here
    【解决方案3】:

    我认为问题在于价值观和西装应该被声明为静态的。

    static string[] values = new string[] { "9", "10", "J", "Q", "K", "A" };
    static string[] suits = new string[] { "clubs", "spades", "hearts", "diamonds" };
    

    这样,它们将在实例化新类时可用。

    【讨论】:

      猜你喜欢
      • 2012-12-10
      • 1970-01-01
      • 1970-01-01
      • 2013-11-15
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 2019-01-14
      相关资源
      最近更新 更多