[英]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的内部,但是我认为这是一个草率的答案,因为后来有人想创建自己的Foo
或Baz
类型(可能会发生)将被默认的CreateBar()
实现卡住,该实现可能会也可能无法满足他们的需求。
也许有一种方法可以使其重构以使其正常工作? 我正在尝试在墙上砸头,尝试进行设计以使其正常运行。
编辑(更多信息):
稍微具体一点:Foo正在实现IEnumerable,并且长话短说,Bar提供了相同的接口,但只提供了该可枚举对象的有限子集。 所有Foo都应该能够创建自己的子集(例如Bar)并将其返回。 但是我不想让每个想要实现Foo的人都为此而担心,因为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.