case of friend classes in C#

Consider the following code pattern:

// 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;
}

Problem: there is no way to create a new Foo and update both m_foos list in the FooManager, and m_manager reference in the new Foo instance without exposing some privates publicly (and running the risk of someone desyncing the list with actual Foos).

Eg one could implement a constructor Foo(FooManager manager) in Foo. It could set m_manager reference, but it has no way to access the m_foos list. Or you could implement CreateFoo() method in the manager. It can access m_foos list, but it has no way to set m_manager in Foo.

In C++, one would obviously declare FooManager a friend of Foo to express the design intent, but this is not possible in C#. I also know that I could make Foo an inner class of FooManager to gain access, but this is not a solution either (what if Foo could belong to more than one manager class?)

Btw. I know about "internal" access in .NET, but it requires that Foo and FooManager live on their own in a separate assembly, which is not acceptable.

Any workarounds for that without making private stuff public?


如果我理解正确:

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;
    }
}

One option would be to use a private nested class for Foo that implements a public interface:

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;
        }
    }
}

As the Foo class is a private nested class, it can't be created outside the FooManager, and so FooManager's CreateFoo() method ensures that everything stays in-sync.


What you can do is create your classes inside a different kind of namespace, let's call it a "module" (don't be fooled by the class keyword, this is not a real class):

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);
    }
  }

}

Since the "module" is a partial class, you can still create other members inside it in other files in the same compilation unit.

链接地址: http://www.djcxy.com/p/82180.html

上一篇: 什么是私人界面?

下一篇: C#中的好友类的情况