簡體   English   中英

C#中的朋友類用例的解決方法

[英]Workaround for an use-case of friend classes in 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()方法可確保所有內容保持同步。

你可以做的是在不同類型的命名空間內創建你的類,讓我們稱它為“模塊”(不要被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);
    }
  }

}

由於“模塊”是一個部分類,您仍然可以在同一編譯單元的其他文件中創建其中的其他成員。

我正在考慮使用反射。

對於失敗的設計(CLR中缺少朋友)沒有好的解決方案。

這樣的事情怎么樣:

public class FriendClass
{
     public void DoSomethingInMain()
     {
         MainClass.FriendOnly(this);
     }
}

public class MainClass
{
    public static void FriendOnly(object Caller)
    {
        if (!(Caller is FriendClass) /* Throw exception or return */;

        // Code
    }
}

當然,這並不妨礙用戶做這樣的事情:

public class NonFriendClass
{
    public void DoSomething()
    {
         MainClass.FriendOnly(new FriendClass());
    }
}

我想可以有辦法解決這個問題,但我的任何想法都開始變得過度。

有一個基類怎么樣:

class FooBase
{
     protected static readonly Dictionary<Foo,FooManager> _managerMapping = new Dictionary<Foo,FooManager>();
}

然后Foo和FooManager將FooBase作為基類,可以更新它們的映射,而不會在外部暴露它。 然后你可以確定沒有人會從外面改變這個集合。

然后在Foo中你有一個屬性Manager ,它將返回與它相關的管理器和類似的,在Manager中的Foos屬性將給出所有Foos。

在這個例子中,唯一可以使關系不同步的是Foo和Manager本身。 在管理器上調用CreateFoo()來創建“托管foo”。 其他人可以創建一個Foo,但是如果沒有經理“同意”,他們就無法讓它由管理者管理。

public class Foo
{
    private FooManager m_manager;

    public void SetManager(FooManager manager)
    {
        if (manager.ManagesFoo(this))
        {
            m_manager = manager;
        }
        else
        {
            throw new ArgumentException("Use Manager.CreateFoo() to create a managed Foo");
        }
    }
}

public class FooManager
{
    private List<Foo> m_foos = new List<Foo>();

    public Foo CreateFoo()
    {
        Foo foo = new Foo();
        m_foos.Add(foo);
        foo.SetManager(this);

        return foo;
    }

    public bool ManagesFoo(Foo foo)
    {
        return m_foos.Contains(foo);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM