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()' 由于其保护级别而无法访问
。
我不希望构造函数是公共的,只有从 Foo
继承的类才应该能够创建 Bar
。 Bar
是一种专门的 Foo
,任何类型的 Foo
都应该能够创建一个。 公共内部在这里是一个“选项”,因为 Foo
的大多数预定义扩展都将在 DLL 内部,但我认为这是一个草率的答案,因为后来出现的任何人想要创建他们自己的 Foo
或 Baz
类型(这很可能发生)将被默认的 CreateBar()
实现所困扰,这可能会或可能会发生不能满足他们的需求。
也许有一种方法可以重构它以使其正常工作? 我正在把头撞在墙上,试图设计这个,所以它会起作用。
编辑(更多信息):
稍微具体一点:Foo正在实现IEnumerable,长话短说,Bar正在提供相同的接口,但只针对该可枚举对象的有限子集。 所有 Foo 都应该能够创建它们自己的子集(即 Bar)并返回它。 但我不希望每个想要实现 Foo 的人都必须担心这一点,因为 Bar 将进行代理并担心限制范围等。
Given the following inheritance tree, what would be the best way of implementing it in a way that works?
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);
}
}
This fails with: 'Bar.Bar()' is inaccessible due to its protection level
.
I don't want the constructor being public, only classes that inherit from Foo
should be able to create Bar
s. Bar
is a specialised Foo
, and any type of Foo
should be able to create one. Public internal is an 'option' here, as the majority of the predefined extensions to Foo
will be internal to the DLL, but I consider this a sloppy answer, since anyone who comes along later who wants to create their own type of Foo
or Baz
(which is likely to happen) will be stuck with a default CreateBar()
implementation, which may or may not meet their needs.
Perhaps there is a way of refactoring this to make it work nicely? I'm banging my head on the wall trying to design this so it'll work though.
Edit (More info):
Slightly more concrete: Foo is implementing IEnumerable and long story short, Bar is providing the same interface, but to a limited subset of that enumerable object. All Foo's should be able to create subsets of themselves (ie. Bar) and return it. But I don't want to have everyone who ever wants to implement a Foo to have to worry about this, because Bar will do the proxying and worry about limiting the range, etc.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
好的,新答案:
编辑:对此的一种变体是使 Bar 成为 Foo 中受保护的嵌套类,并具有公共构造函数。 这样,任何派生类都能够为自己实例化它,但不相关的类根本无法“看到”它。 您仍然需要将接口与实现分开(以便接口可以是公共的),但我认为无论如何这是一件好事。
Okay, new answer:
EDIT: One variant on this would be to make Bar a protected nested class within Foo, with a public constructor. That way any derived class would be able to instantiate it for themselves, but no unrelated class would be able to "see" it at all. You'd still need to separate the interface from the implementation (so that the interface can be public) but I think that's a good thing anyway.
您是否可以将 Baz 设为 Bar 中的嵌套类型? 这是您赋予它比其他方式更多的 Bar 访问权限的唯一方法。 仅具有相同的父类只能使其访问 Foo 的受保护成员,而 Foo 没有对 Bar 的特殊访问权限。 我怀疑还有其他曲折的方法可以用嵌套类型来做到这一点,但实际上这对于维护工程师来说是非常不愉快的。
不过,强制一个派生类创建从同一基类派生的不同类的实例是一种相当奇怪的设计。 这真的是您所需要的吗? 也许如果你用更具体的术语来说,就会更容易提出替代设计。
Would it be possible for you to make Baz a nested type within Bar? That's the only way you'll give it more access to Bar than it would otherwise have. Just having the same parent class only gives it access to protected members of Foo, and Foo doesn't have special access to Bar. I suspect there are other tortuous ways of doing this with nested types, but really it's going to be quite unpleasant for maintenance engineers.
It's quite an odd design though, to force one derived class to create an instance of a different class derived from the same base class. Is that really what you need? Perhaps if you put this in more concrete terms it would be easier to come up with alternative designs.
您可以通过 Foo 中的嵌套类型访问 Bar 的构造函数:
You can access Bar's constructor through a nested type within Foo:
暂时忘记 Bar 源自 Foo。 如果你这样做,听起来问题是“如何让 Foo 的每个子类都可以创建一个 Bar,即使子类无权访问 Bar 的构造函数?”
这是一个很容易解决的问题:
如果您想保证 Foo 的子类无法访问 Bar 的构造函数,请将它们放在不同的程序集中。
现在,要从 Foo 派生 Bar,只需进行一个简单的更改:
“我不希望构造函数是公共的。” 查看。
“只有从 Foo 继承的类才应该能够创建 Bar。” 查看。
“任何类型的 Foo 都应该能够创建一个。” 检查一下,
“任何后来想要创建自己类型的 Foo 或 Baz(这很可能发生)的人都会被默认的 CreateBar() 实现所困扰,这可能会也可能不会满足他们的需求。” 我认为,这很大程度上取决于 Foo.CreateBar() 方法中发生的情况。
Forget, for a moment, that Bar derives from Foo. If you do this, it sounds like the problem is "How do I make it so that every subclass of Foo can create a Bar, even if the subclass doesn't have access to Bar's constructor?"
That's a pretty easy problem to solve:
If you want to guarantee that the subclasses of Foo don't have access to Bar's constructor, put them in a different assembly.
Now, to derive Bar from Foo, it's a simple change:
"I don't want the constructor being public." Check.
"Only classes that inherit from Foo should be able to create Bars." Check.
"Any type of Foo should be able to create one." Check,
"Anyone who comes along later who wants to create their own type of Foo or Baz (which is likely to happen) will be stuck with a default CreateBar() implementation, which may or may not meet their needs." This is pretty highly dependent on what has to happen in the Foo.CreateBar() method, I think.
C# 不提供与 C++ 的friend 关键字直接等效的关键字。 看来您的设计需要这种构造。
在 C++ 中,您可以使用“friend”指定特定类可以访问另一个类的私有/受保护成员。 注意:这与 C# 的内部修饰符不同,后者允许访问同一程序集中的所有类。
看看你的设计,你似乎正在尝试做一些需要 C++ 风格朋友的事情。 Jon Skeet 是对的,C# 中弥补这一点的通常设计是使用嵌套类。
此论坛帖子进一步解释并显示了如何执行此操作的一些示例。
C# doesn't provide a direct equivalent of the C++ friend keyword. Seems like your design is requiring this sort of construct.
In C++ you could designate that a specific class has access to the private/protected members of another class by using "friend". Note: this is not the same as C# internal, modifier which gives access to all classes within the same assembly.
Looking at your design, it seems you are trying to do something along the lines that would require the C++ style friend. Jon Skeet is right, the usual design in C# to make up for this is to use a nested class.
This forum post explains further and shows some examples of how to do this.