Есть ли в C # 4.0 способ сделать закрытый член одного класса доступным только для определенного другого класса?

Мы создаем иерархию объектов, в которой каждый элемент имеет набор других элементов, и каждый элемент также имеет свойство Parent , указывающее на его родительский элемент. Довольно стандартный материал. У нас также есть класс ItemsCollection , который наследуется от Collection , который сам имеет свойство Owner , указывающее на элемент, которому принадлежит коллекция. Опять же, ничего интересного.

Когда элемент добавляется в класс ItemsCollection , мы хотим, чтобы он автоматически устанавливал родительский элемент для Item (используя свойство коллекции Owner ) и когда элемент удален, мы хотим очистить родительский элемент.

Вот в чем дело. Мы только хотим, чтобы установщик Parent был доступен для ItemsCollection , и ничего больше. Таким образом, мы можем не только узнать, кто является родительским элементом элемента, но и убедиться, что элемент не добавлен в несколько коллекций, проверив существующее значение в Parent или позволив кому-либо произвольно его изменить к чему-то другому.

Мы знаем, как это сделать двумя способами:

  1. Отметить установщик как частный, а затем заключить определение коллекции в область действия самого элемента. Плюс: Полная защита. Против: Уродливый код с вложенными классами.

  2. Используйте частный интерфейс ISetParent для Item, о котором знает только ItemsCollection . Плюсы: гораздо более чистый код и простой в использовании. Против: Технически любой, кто знает интерфейс, может использовать Item и получить доступ к сеттеру.

Теперь технически посредством отражения любой может получить что угодно в любом случае, но все же ... пытаясь найти лучший способ сделайте это.

Теперь я знаю, что в C ++ есть функция под названием Friend или что-то, что позволяет вам назначать в противном случае закрытый член в одном классе как доступный для другого, что было бы идеальным сценарием, но я не знаю ничего подобного в C #.

В псевдокоде (например, все уведомления об изменении свойств и тому подобное были удалены для краткости, и я просто набираю это здесь, а не копирую из кода) у нас есть это .. .

public class Item
{
    public string Name{ get; set; }
    public Item Parent{ get; private set; }
    public ItemsCollection ChildItems;

    public Item()
    {
        this.ChildItems = new ItemsCollection (this);
    }
}

public class ItemsCollection : ObservableCollection<Item>
{
    public ItemsCollection(Item owner)
    {
        this.Owner = owner;
    }   

    public Item Owner{ get; private set; }

    private CheckParent(Item item)
    {
        if(item.Parent != null) throw new Exception("Item already belongs to another ItemsCollection");
        item.Parent = this.Owner; // <-- This is where we need to access the private Parent setter
    }

    protected override void InsertItem(int index, Item item)
    {
        CheckParent(item);
        base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
        this[index].Parent = null;
        base.RemoveItem(index);
    }

    protected override void SetItem(int index, Item item)
    {
        var existingItem = this[index];

        if(item == existingItem) return;

        CheckParent(item);
        existingItem.Parent = null;

        base.SetItem(index, item);
    }

    protected override void ClearItems()
    {
        foreach(var item in this) item.Parent = null; <-- ...as is this
        base.ClearItems();
    }

}

Есть ли другой способ сделать что-то подобное?

20
задан MarqueIV 7 July 2011 в 16:13
поделиться