鉴于以下继承树,以一种有效的方式实现它的最佳方法是什么?

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()'由于其保护级别而无法访问。

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

也许有一种方法可以重构它以使其工作得很好?我正试图设计这个,所以它会起作用。

修改(更多信息):

略微更具体:Foo正在实现IEnumerable和长话短说,Bar提供相同的接口,但是对于该可枚举对象的有限子集。所有Foo应该能够创建自己的子集(即Bar)并返回它。但是我不希望每个想要实现Foo的人都不必担心这个问题,因为Bar会做代理并担心限制范围等。

有帮助吗?

解决方案

好的,新答案:

  1. 将栏拆分为界面和具体类。
  2. 用IBar表达公共抽象方法。
  3. 使Bar成为Foo中的私有嵌套类,实现IBar。给它一个内部构造函数,你可以从Foo调用它。
  4. 在Foo中编写一个受保护的方法,它从自身创建一个Bar实例。如果仅仅代理足够好,那么从Foo派生的类可以使用它来实现抽象方法,而具有更复杂需求的类可以直接实现IBar。您甚至可以将抽象方法更改为虚拟方法,并从“this”创建一个新的Bar。默认情况下。
  5. 编辑:关于这个的一个变体是使用公共构造函数在Foo中使Bar成为 protected 嵌套类。这样,任何派生类都能够自己实例化它,但没有不相关的类能够“看到”它们。它一点都没有。您仍然需要将接口与实现分开(以便接口可以公开)但我认为这无论如何都是好事。

其他提示

你有可能让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继承的类才能创建Bars。”检查。

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

“任何想要创建自己类型的Foo或Baz(可能会发生)的人都会遇到默认的CreateBar()实现,这可能会或可能不会满足他们的需求。”我认为这非常依赖于Foo.CreateBar()方法中发生的事情。

C#不提供C ++好友关键字的直接等价物。好像你的设计需要这种结构。

在C ++中,您可以通过使用“friend”指定特定类可以访问另一个类的私有/受保护成员。注意:这与C#internal,modifier不同,它允许访问同一程序集中的所有类。

看看你的设计,你似乎正在尝试做一些需要C ++风格的朋友。 Jon Skeet是对的,C#中常用的设计就是使用嵌套类。

论坛帖子进一步说明,并展示了如何执行此操作的一些示例。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top