鉴于以下继承树,以一种有效的方式实现它的最佳方法是什么?
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
。公共内部在这里是一个“选项”,因为Foo
的大多数预定义扩展都是DLL内部的,但我认为这是一个草率的答案,因为后来有人想要创建自己的类型Baz
或CreateBar()
(可能会发生)将会遇到默认{{1}}实施,这可能会或可能不会满足他们的需求。
也许有一种方法可以重构它以使其工作得很好?我正试图设计这个,所以它会起作用。
修改(更多信息):
略微更具体:Foo正在实现IEnumerable和长话短说,Bar提供相同的接口,但是对于该可枚举对象的有限子集。所有Foo应该能够创建自己的子集(即Bar)并返回它。但我不希望每个想要实现Foo的人都不必担心这个问题,因为Bar会做代理并担心限制范围等。
答案 0 :(得分:4)
好的,新答案:
编辑:关于这个的一个变体是使用公共构造函数在Foo中使Bar成为 protected 嵌套类。这样任何派生类都可以自己实例化它,但没有不相关的类能够“看到”它。您仍然需要将接口与实现分开(以便接口可以公开)但我认为这无论如何都是好事。
答案 1 :(得分:1)
你有可能让Baz成为Bar中的嵌套类型吗?这是你给予Bar更多访问权限的唯一方式。只拥有相同的父类只允许它访问受保护的Foo成员,而Foo没有对Bar的特殊访问权限。我怀疑使用嵌套类型还有其他一些曲折的方法,但实际上对于维护工程师来说这将是非常不愉快的。
这是一个非常奇怪的设计,强制一个派生类创建一个派生自同一基类的不同类的实例。这真的是你需要的吗?也许如果你用更具体的术语来说,提出替代设计会更容易。
答案 2 :(得分:1)
您可以通过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);
}
}
答案 3 :(得分:1)
暂时忘记,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()方法中发生的事情。
答案 4 :(得分:0)
C#不提供C ++好友关键字的直接等价物。好像你的设计需要这种结构。
在C ++中,您可以使用“friend”指定特定类可以访问另一个类的私有/受保护成员。注意:这与C#internal,modifier不同,它允许访问同一程序集中的所有类。
看看你的设计,你似乎正在尝试做一些需要C ++风格的朋友。 Jon Skeet是对的,C#中常用的设计就是使用嵌套类。
此forum post进一步说明,并展示了如何执行此操作的一些示例。