繁体   English   中英

C#中的继承树和受保护的构造函数

[英]Inheritance trees and protected constructors in C#

给定以下继承树,以一种可行的方式实现它的最佳方法是什么?

abstract class Foo<T> : IEnumerable<T>
{
    public abstract Bar CreateBar();
}

class Bar<T> : Foo<T>
{
    // Bar's provide a proxy interface to Foo's and limit access nicely.
    // The general public shouldn't be making these though, they have access
    // via CreateBar()
    protected Bar(Foo base)
    {
        // snip...
    }
}

class Baz<T> : Foo<T>
{
    public Bar CreateBar()
    {
        return new Bar(this);
    }
}

失败并显示: 'Bar.Bar()' is inaccessible due to its protection level

我不希望构造函数是公共的,只有继承自Foo类才能够创建Bar Bar是专门的Foo ,任何类型的Foo都应该可以创建一个。 公共内部在这里是一个“选项”,因为大多数Foo的预定义扩展都将在DLL的内部,但是我认为这是一个草率的答案,因为后来有人想创建自己的FooBaz类型(可能会发生)将被默认的CreateBar()实现卡住,该实现可能会也可能无法满足他们的需求。

也许有一种方法可以使其重构以使其正常工作? 我正在尝试在墙上砸头,尝试进行设计以使其正常运行。

编辑(更多信息):

稍微具体一点:Foo正在实现IEnumerable,并且长话短说,Bar提供了相同的接口,但只提供了该可枚举对象的有限子集。 所有Foo都应该能够创建自己的子集(例如Bar)并将其返回。 但是我不想让每个想要实现Foo的人都为此而担心,因为Bar会做代理并且担心限制范围等。

好的,新答案:

  1. 将Bar拆分为一个界面和一个具体的类。
  2. 用IBar表示公共抽象方法。
  3. 使Bar在Foo中成为私有嵌套类,实现IBar。 给它一个内部构造函数,您可以从Foo调用它。
  4. 在Foo中编写一个受保护的方法,该方法从自身创建Bar的实例。 如果仅代理就足够了,则从Foo派生的类可以使用此方法来实现抽象方法,而具有更复杂需求的类可以直接实现IBar。 您甚至可以将抽象方法更改为虚拟方法,并默认情况下从“ this”创建一个新的Bar。

编辑:对此的一种变体是使用公共构造函数使Bar成为Foo中受保护的嵌套类。 这样,任何派生类都可以自己实例化它,但是任何不相关的类都将无法“看到”它。 您仍然需要将接口与实现分开(以便接口可以是公共的),但是我认为这还是一件好事。

您能否将Baz设为Bar中的嵌套类型? 这是您为Bar提供比其他方式更多访问权限的唯一方法。 拥有同一个父类只能使它访问Foo的受保护成员,而Foo没有对Bar的特殊访问。 我怀疑使用嵌套类型还有其他曲折的方法,但是对于维护工程师来说,这确实是非常不愉快的。

但是,这是一个很奇怪的设计,它迫使一个派生类创建一个从同一基类派生的不同类的实例。 那真的是您所需要的吗? 也许,如果您用更具体的术语来表达,可能会更容易提出替代设计。

您可以通过Foo中的嵌套类型访问Bar的构造函数:

abstract class Foo<T> : IEnumerable<T>
{
  public abstract Bar<T> CreateBar();

  protected Bar<T> CreateBar(Foo<T> f) { return new FooBar(f); }

  private class FooBar : Bar<T> 
   { public FooBar(Foo<T> f) : base(f) {}   
   }
}

class Bar<T> : Foo<T>
{ protected Bar(Foo<T> @base) {}
}

class Baz<T> : Foo<T>
{
    public override Bar<T> CreateBar() 
    {
        return CreateBar(this);
    }
}

暂时忘了Bar来自Foo。 如果这样做,听起来好像是问题在于“如何做到这一点,以便Foo的每个子类都可以创建Bar,即使该子类无法访问Bar的构造函数?”

这是一个很容易解决的问题:

public class Foo
{
   protected static Bar CreateBarInstance()
   {
      return new Bar();
   }
   public virtual Bar CreateBar()
   {
      return CreateBarInstance();
   }
}

public class Bar
{
    internal Bar()
    {
    }
}

public class Baz : Foo
{
    public override Bar CreateBar()
    {
        Bar b = base.CreateBar();
        // manipulate the Bar in some fashion
        return b;
    }
}

如果要保证 Foo的子类无法访问Bar的构造函数,请将它们放在不同的程序集中。

现在,要从Foo派生Bar,这是一个简单的更改:

public class Bar : Foo
{
    internal Bar()
    {
    }
    public override Bar CreateBar()
    {
        throw new InvalidOperationException("I'm sorry, Dave, I can't do that.");
    }

}

“我不希望构造函数公开。” 校验。

“只有从Foo继承的类才可以创建Bar。” 校验。

“任何类型的Foo都应该能够创建一个。” 校验,

“后来出现的任何人想要创建自己的Foo或Baz类型(很可能会发生)都将陷入默认的CreateBar()实现中,这可能会或可能不会满足他们的需求。” 我认为,这很大程度上取决于Foo.CreateBar()方法中发生的事情。

C#不提供与C ++朋友关键字直接等效的内容。 似乎您的设计需要这种构造。

在C ++中,您可以使用“朋友”来指定特定的类可以访问另一个类的私有/受保护成员。 注意:这与C#内部修饰符不同,后者可访问同一程序集中的所有类。

看您的设计,似乎您正在尝试做一些需要C ++风格朋友的事情。 乔恩·斯凯特(Jon Skeet)是对的,用C#弥补这一点的通常设计是使用嵌套类。

论坛帖子进一步解释了该示例,并显示了一些有关如何执行此操作的示例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM