C#中的好友类的情况
考虑以下代码模式:
// Each foo keeps a reference to its manager
class Foo
{
private FooManager m_manager;
}
// Manager keeps a list of all foos
class FooManager
{
private List<Foo> m_foos;
}
问题:没有办法创建一个新的Foo并更新FooManager中的m_foos列表和新的Foo实例中的m_manager引用,而不公开公开地暴露某些私有(并且冒着有人用实际的Foos使列表异化的风险)。
例如,可以在Foo中实现一个构造函数Foo(FooManager manager)。 它可以设置m_manager引用,但无法访问m_foos列表。 或者你可以在管理器中实现CreateFoo()方法。 它可以访问m_foos列表,但无法在Foo中设置m_manager。
在C ++中,显然可以声明FooManager是Foo的一个朋友来表达设计意图,但在C#中这是不可能的。 我也知道我可以让Foo成为FooManager的一个内部类来获得访问权限,但这也不是一个解决方案(如果Foo可能属于多个经理类呢?)
顺便说一句。 我知道.NET中的“内部”访问,但它要求Foo和FooManager独立存在于单独的程序集中,这是不可接受的。
任何解决方法,而不公开私人的东西?
如果我理解正确:
public abstract class FooBus
{
protected static FooBus m_bus;
}
public sealed class Foo : FooBus
{
private FooManager m_manager;
public Foo(FooManager fm)
{
if (fm == null)
{
throw new ArgumentNullException("Use FooManager.CreateFoo()");
}
if (m_bus != fm)
{
throw new ArgumentException("Use FooManager.CreateFoo()");
}
m_manager = fm;
}
}
public class FooManager : FooBus
{
private List<Foo> m_foos = new List<Foo>();
public Foo CreateFoo()
{
m_bus = this;
Foo f = new Foo(this);
m_foos.Add(f);
m_bus = null;
return f;
}
}
一种选择是使用实现公共接口的Foo的私有嵌套类:
public interface IFoo
{
// Foo's interface
}
public sealed class FooManager
{
private readonly List<Foo> _foos = new List<Foo>();
public IFoo CreateFoo()
{
var foo = new Foo(this);
_foos.Add(foo);
return foo;
}
private class Foo : IFoo
{
private readonly FooManager _manager;
public Foo(FooManager manager)
{
_manager = manager;
}
}
}
由于Foo类是一个私有嵌套类,因此无法在FooManager外创建它,因此FooManager的CreateFoo()
方法可确保所有内容保持同步。
你可以做的是在不同类型的命名空间中创建你的类,我们称它为“模块”(不要被类关键字愚弄,这不是真正的类):
public static partial class FooModule {
// not visible outside this "module"
private interface IFooSink {
void Add(Foo foo);
}
public class Foo {
private FooManager m_manager;
public Foo(FooManager manager) {
((IFooSink)manager).Add(this);
m_manager = manager;
}
}
public class FooManager : IFooSink {
private List<Foo> m_foos = new List<Foo>();
void IFooSink.Add(Foo foo) {
m_foos.Add(foo);
}
}
}
由于“模块”是分部类,因此您仍然可以在同一编译单元的其他文件中创建其他成员。
链接地址: http://www.djcxy.com/p/82179.html