【问题标题】:In C# 4.0, is there any way to make an otherwise private member of one class available only to a specific other class?在 C# 4.0 中,有没有办法让一个类的其他私有成员仅对特定的其他类可用?
【发布时间】:2011-09-30 14:43:54
【问题描述】:

我们正在创建一个对象层次结构,其中每个项目都有其他项目的集合,每个项目还有一个指向其父项目的Parent 属性。很标准的东西。我们还有一个ItemsCollection 类,它继承自Collection<Item>,它本身有一个Owner 属性指向集合所属的项目。同样,那里没有什么有趣的。

当一个项目被添加到ItemsCollection 类时,我们希望它自动设置项目的父项(使用集合的Owner 属性),当项目被删除时,我们希望清除父项。

事情就是这样。我们只希望Parent 设置器可用于ItemsCollection,仅此而已。这样,我们不仅可以知道项目的父项是谁,而且我们还可以通过检查 Parent 中的现有值或让某人随意将其更改为其他值来确保不会将项目添加到多个集合中。

我们知道如何做到这一点的两种方法是:

  1. 将 setter 标记为私有,然后将集合定义包含在项目本身的范围内。优点:全面保护。缺点:带有嵌套类的丑陋代码。

  2. 在只有ItemsCollection 知道的Item 上使用私有ISetParent 接口。优点:代码更简洁,易于理解。缺点:从技术上讲,任何了解该界面的人都可以使用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();
    }

}

还有其他类似的方法吗?

【问题讨论】:

标签: c# parent-child private friend


【解决方案1】:

我能想到的只有两件事:

一个:

使用您上面提到的选项编号 2(我自己经常这样做)...但是使接口(项目)的实现成为 ItemsCollection 内的嵌套私有类...只有 @987654322 @知道setter。接口IItem 只为Parent 声明了一个getter...并且没有人可以将它转换为Item,因为Item 是ItemsCollection 的私有。所以,类似:

public class ItemsCollection : ObservableCollection<IItem>
{
    private class Item : IItem 
    {
        public object Parent { get; set; }
    }

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

    public static IItem CreateItem() { return new Item(); }
}

public interface IItem 
{
    object Parent {get; }
}

当您希望 ItemsCollection 设置项目 Parent 时,将 IItem 实例设置为 Item(它确实公开了一个 setter)。只有 ItemsCollection 可以执行此转换,因为 Item 实现是 ItemsCollection 私有的...所以我认为这可以实现您想要的。

二:

将其设为内部而不是私有...您无法得到您想要的,但您可以使用 InternalsVisibleToAttribute 表示内部成员对另一个程序集可见。

【讨论】:

  • 是的,我自己倾向于第一个。你提到的第二个不起作用,因为我们不希望同一个程序集中的项目能够接触到它(因此是私有的,而不是内部的。)但是,并没有真正遵循你的“将接口放在类中”的事情好像只有ItemsCollection类知道接口,Item怎么实现呢?你能举个例子吗?
  • 啊啊……我得说实话。根本不喜欢这个,因为我们的 Item 类的接口非常复杂。这意味着复制界面上的每一个非私有属性,这会很快变得非常混乱。如果我要选择“封闭”选项,我会将public ItemsCollection 放在Item 中,因为至少这样您可以获得与此处相同的结果,但不需要接口。
【解决方案2】:

我用来控制类成员可见性的一种解决方案是将类定义为部分,然后在不同的命名空间中将该类声明为部分,并定义您想要的特殊可见性成员.

这会根据所选的命名空间控制成员的可见性。

您唯一需要考虑的就是引用。它可能会变得复杂,但一旦你弄清楚了,它就会起作用。

【讨论】:

  • 但是如果它们在两个不同的命名空间中,那么它们就不是真正的部分类,而是完全是两个不同的类,这意味着你不能共享成员变量等。“部分”不真正的意思是/做任何事情,而无需至少一个其他文件指向同一命名空间中的同一类。这听起来根本不是一个解决方案。
  • 它们可以是部分类,如果设置正确,它们可以相互引用对方的变量。
  • 很抱歉,但我认为您不太了解部分类的工作原理。这不是运行时的事情,也不是像您建议的那样用于分离功能或范围。只是为了代码组织严格将单个类拆分为多个代码文件,仅此而已。它仍然编译为一个类。此外,部分类需要两个文件指向相同的类在同一个命名空间中,你已经声明你没有。在我看来,这更像是您刚刚将一个班级分成两个独立的不同班级。尝试删除“部分”这个词,我敢打赌它仍然可以编译。
  • 这里有更多信息证实了我的说法:“使用 partial 关键字表示类、结构或接口的其他部分可以定义在 命名空间内。所有部分都必须使用 partial 关键字。所有部分必须在编译时可用以形成最终类型。所有部分必须具有相同的可访问性,例如公共、私有等。"(来源:msdn.microsoft.com/en-us/library/wa80x488(v=vs.80).aspx)
  • 但我 OP! :) 感谢您的尝试。遗憾的是,没有像 C++ 中那样的“朋友”范围,但看起来私有接口在大多数情况下就足够了。再次感谢!
【解决方案3】:

我的答案由两部分组成

  1. 为什么拥有接口 ISetParent 如此“不安全”?

私有/内部访问修饰符是为了防止错误, 不是真正的“安全代码”。

记住...您可以使用一些反射/调用等调用私有方法...

.

2 。我通常把一切都公开 并确保双方都知道如何处理对方,

当然,有一点乒乓球,但只需要几个周期 (在这种情况下,我有一个 NamedSet)

    private IPhysicalObject partOf;
    public IPhysicalObject PartOf
    {
        get { return partOf; }
        set
        {
            if (partOf != value)
            {
                if (partOf != null)
                    partOf.Children.Remove(this.Designation);

                partOf = value;

                if (partOf != null)
                    partOf.Children.Add(this.Designation);
            }
        }
    }

    public virtual void Add(String key, IPhysicalObject value)
    {
        IPhysicalObject o;
        if (!TryGetValue(key, out o))
        {
            innerDictionary.Add(key, value);
            value.PartOf = Parent;
        }
    }

    public virtual bool Remove(String key)
    {
        IPhysicalObject o;
        if(TryGetValue(key, out o))
        {
            innerDictionary.Remove(key);
            o.PartOf = null;
        }
    }

希望这会有所帮助... 再会, 汤姆·W。

附:我永远不会知道这个编辑器是如何工作的……我应该把它变成 HTML 还是不应该?

【讨论】:

  • 感谢您的回复。 Q 现在有点老了,我们有一个解决方法,但我会看看你的建议。 (现在不在我的电脑前。)至于编辑,不要考虑 HTML,而要考虑 Markdown。将 Markdown 视为知道如何以某种格式显示的易读文本。 (只需 google Markdown,或查看那里的任何编辑器。)
【解决方案4】:

你可以使用 Delegates 来做这些事情:

public delegate void ItemParentChangerDelegate(Item item, Item newParent);

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

    static Item()
    {
        // I hereby empower ItemsCollection to be able to set the Parent property:
        ItemsCollection.ItemParentChanger = (item, parent) => { item.Parent = parent };
        // Now I just have to trust the ItemsCollection not to do evil things with it, such as passing it to someone else...
    }
    public static void Dummy() { }

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

public class ItemsCollection : ObservableCollection<Item>
{
    static ItemsCollection()
    {
        /* Forces the static constructor of Item to run, so if anyone tries to set ItemParentChanger,
        it runs this static constructor, which in turn runs the static constructor of Item,
        which sets ItemParentChanger before the initial call can complete.*/
        Item.Dummy();
    }
    private static object itemParentChangerLock = new object();
    private static ItemParentChangerDelegate itemParentChanger;
    public static ItemParentChangerDelegate ItemParentChanger
    {
        private get
        {
            return itemParentChanger;
        }
        set
        {
            lock (itemParentChangerLock)
            {
                if (itemParentChanger != null)
                {
                    throw new InvalidStateException("ItemParentChanger has already been initialised!");
                }
                itemParentChanger = value;
            }
        }
    }

    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;
        ItemParentChanger(item, this.Owner); // Perfectly legal! :)
    }

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

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

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

        if(item == existingItem) return;

        CheckParent(item);
        ItemParentChanger(existingItem, null);

        base.SetItem(index, item);
    }

    protected override void ClearItems()
    {
        foreach(var item in this) ItemParentChanger(item, null);
        base.ClearItems();
    }

【讨论】:

  • 我在这里看到的问题是您正在“更新”“项目”内部的 ItemsCollection。在我们的设计中,该集合已经存在于其他地方,并且 Item 已添加到其中。我们只希望它添加到的集合能够将自己设置为父集合。换句话说,集合是唯一可以设置父项的东西,当它收到一个新的子项时会这样做。
  • 这是一个有效的观点。我修复了它:现在有很多“仪式”或“样板”代码,但我认为它确实有效,不再有这个问题。
【解决方案5】:

您如何确保只有该项目的当前集合才能孤立该项目。这样,当它属于一个集合时,没有其他集合可以设置该项目的父项。您可以使用某种唯一密钥,这样第三方就无法参与:

public sealed class ItemsCollection : ObservableCollection<Item>
{
    private Dictionary<Item, Guid> guids = new Dictionary<Item, Guid>();

    public ItemsCollection(Item owner)
    {
        this.Owner = owner;
    }

    public Item Owner { get; private set; }

    private Guid 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     
        return item.BecomeMemberOf(this);

    }

    protected override void InsertItem(int index, Item item)
    {
        Guid g = CheckParent(item);
        base.InsertItem(index, item);
        guids.Add(item, g);
    }

    protected override void RemoveItem(int index)
    {
        Item item = this[index];
        DisownItem(item);
        base.RemoveItem(index);
    }

    protected override void DisownItem(Item item)
    {
        item.BecomeOrphan(guids[item]);
        guids.Remove(item);            
    }

    protected override void SetItem(int index, Item item)
    {
        var existingItem = this[index];
        if (item == existingItem)
            return;
        Guid g = CheckParent(item);
        existingItem.BecomeOrphan(guids[existingItem]);
        base.SetItem(index, item);
        guids.Add(item, g);
    }

    protected override void ClearItems()
    {
        foreach (var item in this)
            DisownItem(item);
        base.ClearItems();
    }
}




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

    public ItemsCollection ChildItems;

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

    private Guid guid;

    public Guid BecomeMemberOf(ItemsCollection collection)
    {
        if (Parent != null)
            throw new Exception("Item already belongs to another ItemsCollection");
        Parent = collection.Owner;
        guid = new Guid();
        return guid; // collection stores this privately         
    }

    public void BecomeOrphan(Guid guid) // collection passes back stored guid         
    {
        if (guid != this.guid)
            throw new InvalidOperationException("Item can only be orphaned by its current collection");
        Parent = null;
    }
}

显然那里有冗余;项目集合正在存储第二个项目集合(字典)。但是有很多选择可以克服我认为你能想到的问题。在这里就不重要了。

不过,我确实建议您考虑将子项管理任务转移到项类中,并尽可能保持集合“愚蠢”。

编辑:针对您的问题,这如何防止和项目出现在两个ItemsCollections 中:

你问向导的意义是什么。为什么不直接使用集合实例本身?

如果您将 guid 参数替换为集合引用,您可以将一个项目添加到两个不同的集合中,如下所示:

{
    collection1.InsertItem(item);  // item parent now == collection1
    collection2.InsertItem(item);  // fails, but I can get around it:
    item.BecomeOrphan(collection1); // item parent now == null 
    collection2.InsertItem(item);  // collection2 hijacks item by changing its parent (and exists in both collections)
}

现在想象一下用 guid 参数来做这个:

{
    collection1.InsertItem(item);  // item parent now == collection1
    collection2.InsertItem(item);  // fails, so...
    item.BecomeOrphan(????); // can't do it because I don't know the guid, only collection1 knows it.
}

因此,您不能将一个项目添加到多个 ItemsCollection。并且 ItemsCollection 是密封的,因此您不能将其子类化并覆盖其 Insert 方法(即使您这样做了,您仍然无法更改项目的父项)。

【讨论】:

  • 我看到这种方法的问题是您仍然将集合管理的责任放在 Item 类上,而不是集合上。另外,除非我读错了,否则您还要让调用者负责存储,然后传回 GUID,这会使事情变得过于复杂。无论如何,集合如何存储 GUID?更重要的是,为什么?!它不会阻止某人将项目直接插入到多个集合中,除非他们使用此 API,但它不是强制执行的。我承认也许我只是不明白你在这里做什么。
  • 该集合需要保留一个 的字典。 (就我个人而言,我会让项目管理它,而不是集合)。我将编辑我的答案以使其更清晰。请稍后再回来查看。
  • 无论您做什么,都可以将项目插入到多个集合中。但是这样你可以确保只有一个集合可以设置项目的父属性,这就是你似乎在问如何做的事情。
  • 是的,但是现在您有了一个项目集合,维护了第二个项目到密钥对的集合。你没有看到那里的讽刺或冗余吗? ...更不用说使用它的开销了?!正如你所说,它实际上并没有阻止某人将它放入另一个收藏中,这是我们试图阻止的真正问题。
  • @Marq:正如我在(编辑的)答案中提到的,冗余很容易删除,我只是为了练习而忽略了它(只需将您的集合建模为字典)。如果您想阻止该项目被添加到另一个集合中,答案是:您不能。但是,您可以阻止它被添加到另一个 ItemsCollection,而这段代码正是这样做的。
【解决方案6】:

我必须每天解决您的问题,但我不会按照您尝试的方式来解决。

退后一步。你试图解决的根本问题是什么? 一致性。您试图确保“x 是 y 的子代”关系和“y 是 x 的父代”关系始终保持一致。这是一个明智的目标。

您的假设是每个项目都直接知道其子项和其父项,因为子项集合和父项引用存储在本地字段中。这在逻辑上要求当项 x 成为项 y 的子项时,您必须始终更改 x.Parent 和 y.Children。这就提出了您遇到的问题:谁来“负责”确保这两项更改始终如一地进行?以及如何确保只有“负责”代码可以改变父字段?

棘手。

假设我们否定了你的假设。不一定每个项目都知道它的子项和它的父项。

技术#1:

例如,您可以说有一个特殊的项目,称为“宇宙”,它是除自身之外的所有项目的祖先。 “宇宙”可以是一个存储在众所周知的位置的单例。当您向项目询问其父项时,实现可以找到宇宙,然后搜索宇宙的每个后代以寻找该项目,并在您前进时跟踪路径。当您找到该项目时,太好了,您完成了。你回头看看让你到达那里的“路径”,你有父母。更好的是,如果您愿意,您可以提供整个 chain 父母;毕竟,你只是计算出来的。

技术#2:

如果宇宙很大并且需要一段时间才能找到每个项目,那可能会很昂贵。另一种解决方案是让 Universe 包含一个将项目映射到其父项的哈希表,以及将项目映射到其子项列表的第二个哈希表。当您将子 x 添加到父 y 时,“add”方法实际上调用了 Universe 并说“嘿,项目 x 现在是 y 的父项”,并且 Universe 负责更新哈希表。项目不包含任何它们自己的“连接性”信息;这是宇宙强制执行的责任。

不利的一面是宇宙可能包含循环;你可以告诉宇宙 x 是 y 的父级,y 是 x 的父级。如果你想避免这种情况,那么你必须编写一个循环检测器。

技巧#3:

你可以说有两棵树; “真实”树和“立面”树。 真正的树是不可变的和持久的。在真实的树中,每个项目都知道它的孩子,但不知道它的父母。一旦你构建了 不可变 真实树,你就可以创建一个外观节点,它是真实树根的代理。当您向该节点询问其子节点时,它会为每个子节点创建一个新的外观节点,并将外观节点的 parent 属性设置为为其子节点查询的节点。

现在您可以将外观树视为父树,但父关系仅在您遍历树时计算。

当您想要编辑树时,您会生成一棵新的真实树,并尽可能多地重复使用旧的真实树。然后创建一个新的外观根。

这种方法的缺点是,它只有在每次编辑后通常从上到下遍历树时才有效。

我们在 C# 和 VB 编译器中使用后一种方法,因为这正是我们所处的情况:当我们在代码编辑后重建解析树时,我们可以重用前面文本中的大部分现有不可变解析树.我们总是从上到下遍历树,只在必要时计算父引用。

【讨论】:

  • @MarqueIV:一个更好的类比——一个更现实的类比——是“公众”是宇宙中的每个人,“内部”是每个在工作中为您的团队工作的人,而“内部人员”对朋友大会可见”是为贵公司工作的每个人。如果您不能相信团队中的人不会滥用程序集的内部结构,那么结交更好的同事创建更好的代码审查文化
  • 这就是我要说的……看看这一切!这是一个类比:一个母亲、一个父亲和他们的孩子在一个购物中心。你有公众:整个世界。内部:商场里的人。私人的:个别的人。 Caley 和妈妈在一起,而爸爸在 Bose 商店。妈妈是监护人。后来,爸爸带走了 Caley,妈妈打了 Scents-R-Us!凯莉的监护人因为是监护人而被妈妈改成了爸爸。虽然商场里的任何人都可以与妈妈、爸爸或凯莉交谈,但只有妈妈或爸爸可以分配监护人的角色,她知道她现在的监护人是谁。家人==朋友。
  • @MarqueIV:两个班级之间没有“朋友”的原因是它很快就会演变成“内部”。我曾经在一个团队工作,该团队制作了一个用 C++ 编写的相当小的库,其中“朋友”这个词在源代码中出现了 七百次。现在,仅仅因为一个特性可以被滥用,没有理由不添加它;所有功能都可能被滥用。但我认为有理由说你可以相信你的同事不会滥用你的内部实现细节。
  • 很抱歉出现故障。以为我丢失了编辑并重新输入了所有内容。虽然我同意“信任你的团队”理论,但可以提出同样的论点,你不需要“私人”。只是“内部”或“公共”。毕竟,如果内部是您团队中的每个人,而您只是“信任”他们,那为什么还要私有呢? “乔……我知道你可以看到这个,但不要碰它!” “当然,马克!” ……“嗯……乔?!” ……‘呃……对不起!它很闪亮!......我错过了备忘录! Friend 按照设计者的要求将责任放在编译器上。不需要“信任”。
  • 今天因为有人投票支持了这个问题。只需重新阅读这篇已有两年历史的文章,我不得不说我仍然支持 C# 中对 Friend 的需求。解决您的“幂等”评论,对我而言,不同之处在于,在这种情况下,您必须看到它,因为即使您只应该调用它一次,您也必须看到它才能调用它。我正在谈论的情况有所不同,因为他们从不有理由调用 SetParent,因此 IMO 应该对他们隐藏 setter。无论如何,这是我的 1.37 美元(这是 2c 加上两年的通货膨胀。)
【解决方案7】:

这个场景让我印象深刻的第一件事是,ItemCollection 和 Item 之间存在一定的功能嫉妒。我理解您希望将子项添加到集合并将父项设置为自主操作,但实际上我认为维护这种关系的责任在于 Item,而不是 ItemCollection。

我建议将 Item 上的 ChildItems 公开为只读集合(可能使用 IEnumerable&lt;Item&gt;),并将 AddChild(Item child)RemoveChild(Item child)ClearChildren() 等方法放在 Item 上。这使您有责任在不担心泄漏到其他类的情况下使用 Item 维护父级。

【讨论】:

  • 是的...想过这个问题,但对我来说,真正处理其中内容的是集合,而不是里面的项目。另外,对我来说,枚举员应该在您正在执行的课程中。我不应该想'要添加我使用这个类,但要枚举,我使用那个。此外,当一个项目有多个子集合(我们实际上有三个)时,在我的解决方案中,每个集合都可以自己管理。你的意思是为 Item 上的每个新类型创建另一个新的添加/删除接口,这甚至不包括需要更多的插入或替换。
  • 您始终可以让您的项目表现得像一个集合,或者让您的集合表现得像一个项目......这取决于您想要如何建模事物。我想到的另一种方法:使设置器受保护,并向集合添加项目子类型(带有复制构造函数的东西)。不过,这仍然不能解决我心中的功能嫉妒问题。
【解决方案8】:

这是一种可以在 C# 中模拟 friend 的方法:

标记您的属性internal,然后使用此属性将它们公开给friend 程序集:

[assembly: InternalsVisibleTo("Friend1, PublicKey=002400000480000094" + 
                              "0000000602000000240000525341310004000" +
                              "001000100bf8c25fcd44838d87e245ab35bf7" +
                              "3ba2615707feea295709559b3de903fb95a93" +
                              "3d2729967c3184a97d7b84c7547cd87e435b5" +
                              "6bdf8621bcb62b59c00c88bd83aa62c4fcdd4" +
                              "712da72eec2533dc00f8529c3a0bbb4103282" +
                              "f0d894d5f34e9f0103c473dce9f4b457a5dee" +
                              "fd8f920d8681ed6dfcb0a81e96bd9b176525a" +
                              "26e0b3")]

public class MyClass {
   // code...
}

【讨论】:

  • 听起来他不希望它们在程序集中可见,事实上恰恰相反,他希望它们非常仅限于特权阶层。
  • James 的评估是正确的,但我还是要投票赞成,因为知道这真是太酷了!谢谢! :)
  • 它是:-) 顺便说一下,如果程序集被强命名(签名),你只需要那里的公钥混乱。我经常使用这个技巧让我在一个单独的单元测试程序集中对一个程序集的内部类进行单元测试。
  • 有趣的是,它实际上看起来非常接近 Friend 过去所做的事情。你可以说 [PrivatesVisibleTo:foo] 或类似的东西。那会很甜蜜。唉,只有……
  • 但是,不要在公共场合这么说。你会被逮捕的! :)
【解决方案9】:

C# 没有 friend 关键字,但它有一个接近的东西,称为 internal。您可以将要以有限方式公开的方法标记为内部方法,然后只有该程序集中的其他类型才能看到它们。如果你所有的代码都在一个程序集中,这对你没有多大帮助,但如果这个类被打包在一个单独的程序集中,它会起作用。

public class Item
{
    public string Name{ get; set; }
    public Item Parent{ get; internal set; } // changed to internal...
    public ItemsCollection ChildItems;

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

【讨论】:

  • 我个人喜欢 JeffN825 的 #1 选项。我只推荐 internal 如果你的代码在类库中隔离得相当好,它通常不会对整个应用程序可见。
猜你喜欢
  • 1970-01-01
  • 2012-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-10
  • 1970-01-01
  • 2012-09-03
  • 1970-01-01
相关资源
最近更新 更多