在C#4.0中,有没有什么办法能让一个可用类的,否则私有成员只对特定的其他类? [英] In C# 4.0, is there any way to make an otherwise private member of one class available only to a specific other class?

查看:293
本文介绍了在C#4.0中,有没有什么办法能让一个可用类的,否则私有成员只对特定的其他类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在创建一个对象层次,其中每个项目都有其他项目的集合,每个项目也有一个指向它的父项属性。漂亮的标准的东西。我们也有从继承收藏℃的 ItemsCollection 类;项目> 它本身有一个所有者属性指向集合所属的项目。同样,没有什么有趣的存在。

We're creating an object hierarchy where each item has a collection of other items, and each item also has a Parent property pointing to its parent item. Pretty standard stuff. We also have an ItemsCollection class that inherits from Collection<Item> which itself has an Owner property pointing to the item the collection belongs to. Again, nothing interesting there.

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

When an item is added to the ItemsCollection class, we want it to automatically set the parent of Item (using the collection's Owner property) and when the item is removed, we want to clear the parent.

这里的事情。我们只希望二传可用以 ItemsCollection ,没有别的。我们这样不但可以知道一个项目的父母是谁,但我们也可以确保项目没有通过检查现有值家长加入到多个集合 ,或让别人随意将其更改为别的东西。

Here's the thing. We only want the Parent setter to be available to ItemsCollection, nothing else. That way not only can we know who the parent of an item is, but we can also ensure an item isn't added to multiple collections by checking for an existing value in Parent, or letting someone arbitrarily change it to something else.

我们知道如何做到这一点有两种方式:

The two ways we know how to do this are:

标记设置器为私有,然后附上项目本身的范围之内的集合的定义。优点:全面保护。缺点:与嵌套类丑陋的代码

  1. Mark the setter as private, then enclose the collection definition within the scope of the item itself. Pro: Full protection. Con: Ugly code with nested classes.

使用上项目的私人 ISetParent 接口,仅 ItemsCollection 知道。优点:更清洁的代码和易于遵循。缺点:技术上任何接口的,谁知道可以施放项目,并获得了二传手

Use a private ISetParent interface on Item that only ItemsCollection knows about. Pro: Much cleaner code and easy to follow. Con: Technically anyone who knows of the interface can cast Item and get at the setter.

现在在技术上通过反射任何人都可以在任何事情,无论如何,但还是试着找做到这一点的最好办法。

Now technically via reflection anyone can get at anything anyway, but still... trying to find the best way to do this.

现在我知道有C ++中的功能叫做朋友,或者让你在一个类中指定一个,否则私有成员为可用另一个这将是完美的情况下的东西,但我不知道在C#中的任何这样的事情。

Now I know there was a feature in C++ called Friend or something that let you designate an otherwise private member in one class as being available to another which would be the perfect scenario, but I don't know of any such thing in C#.

在伪代码(如所有的财产变化通知和这样已经为简洁,删除,我只是打字这在这里,而不是从代码拷贝),我们有这样的...

In pseudocode (e.g. all the property changed notifications and such have been removed for brevity and I'm just typing this here, not copying from code), we have this...

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

}



任何其他方式做同样的事情?

Any other way to do something similar?

推荐答案

我每天都为您解决问题,但我不这样做你想要做的方式它。

I have to solve your problem every day, but I don't do it the way you're trying to do it.

退一步。什么是你想解决根本问题? 一致性的。您正在试图确保X是Y A子关系和y是x的父的关系始终保持一致。这是一个明智的目标。

Take a step back. What is the fundamental problem you're trying to solve? Consistency. You are trying to ensure that the "x is a child of y" relationship and the "y is the parent of x" relationship are always consistent. That's a sensible goal.

您的假设是,每一个项目直接都知道它的孩子及其父因为孩子们收集和家长参考以场存储在本地。这在逻辑上要求,当项x成为项目y的孩子,你必须始终同时改变x.Parent和y.Children。呈现你碰到的问题:谁可以成为一把手,确保这两个变化是一贯做的?你如何保证的只有的的一把手代码获取变异父字段?

Your supposition is that every item directly knows both its children and its parent because the children collection and the parent reference are stored locally in fields. This logically requires that when item x becomes a child of item y, you have to consistently change both x.Parent and y.Children. That presents the problem that you've run into: who gets to be "in charge" of making sure that both changes are made consistently? And how do you ensure that only the "in charge" code gets to mutate the parent field?

整蛊。

假如我们拒绝您的假设。它不需要每一个项目都知道它的孩子及其母公司的情况。

Suppose we denied your supposition. It need not be the case that every item knows both its children and its parent.

例如,你可以说,有一个叫专项宇宙,这是每一个项目,除了本身的祖先。 宇宙可能是存储在一个众所周知的位置是独生子。当你问一个项目其父,实施能找到宇宙,然后做一个搜索宇宙中寻找项目的每一个后代,保持路径的跟踪,当您去。当你找到的项目,太棒了,你就大功告成了。你看起来退一万步说把你那里的路径上,和你有父。更妙的是,你可以提供整个的的父母,如果你想; 。毕竟,你只是计算它

For example, you could say that there is one special item called "the universe", which is the ancestor of every item except itself. "The universe" could be a singleton stored in a well-known location. When you ask an item for its parent, the implementation could find the universe, and then do a search of every descendant of the universe looking for the item, keeping track of the path as you go. When you find the item, great, you're done. You look one step back on the "path" that got you there, and you have the parent. Even better, you can provide the entire chain of parents if you want; after all, you just computed it.

这可能是昂贵的,如果宇宙是大,它需要一段时间才能找到每一个项目。另一种解决方案是将有宇宙包含映射项目给父母一个哈希表,映射项目给孩子列表的第二哈希表。当您添加子X要父母Y,添加方法实际上调用了宇宙,并说:嘿,项x现在由y父,而宇宙需要更新哈希表的照顾。项目不包含任何自己的连通性的信息; 。这就是宇宙强制执行的责任

That could be expensive if the universe is large and it takes a while to find each item. Another solution would be to have the universe contain a hash table that maps items to their parents, and a second hash table that maps items to a list of their children. When you add child x to parent y, the "add" method actually calls the Universe and says "hey, item x is now parented by y", and the Universe takes care of updating the hash tables. Items do not contain any of their own "connectedness" information; that's the responsibility of the universe to enforce.

一个向下的那面是有可能的宇宙则包含循环;你可以告诉宇宙X是由y父和y为x父。如果要避免这种情况,那么你就得写一个周期的检测器。

A down side of that is it is possible for the universe to then contain cycles; you could tell the universe that x is parented by y and y is parented by x. If you wish to avoid this then you'd have to write a cycle detector.

您可能会说,有两棵树; 真正的树和门面树。 真正的树是不可变的和持久性即可。在真正的树,每一个项目都知道它的孩子,但不是它的母公司。一旦你已经建立了的一成不变的真正的树,您这是一个代理到真正的树的根门面节点。当你问及其子节点,这让周围的每一个孩子的裹着一个新的门面节点并设置门面节点被查询及其子节点的parent属性。

You could say that there are two trees; the "real" tree and the "facade" tree. The real tree is immutable and persistent. In the real tree, every item knows its children but not its parent. Once you have built the immutable real tree, you make a facade node that is a proxy to the root of the real tree. When you ask that node for its children, it makes a new facade node wrapped around each child and sets the parent property of the facade node to the node that was queried for its children.

现在,你可以把门面树作为一个与父母的树,但你遍历树父关系只计算。

Now you can treat the facade tree as a parented tree, but the parent relationships are only computed as you traverse the tree.

当你要编辑的树,就产生一个新的真正的树,再利用尽可能多的旧真正的树成为可能。然后,您创建一个新的门面根。

When you want to edit the tree, you produce a new real tree, re-using as much of the old real tree as possible. You then make a new facade root.

这种方法的缺点是,它只有在你通常遍历从顶部树中的每个编辑下来后的作品。

The downside of this approach is that it only works if you typically traverse the tree from the top down after every edit.

我们使用在C#和VB编译器后一种方法,因为这正是我们的情况:当我们代码的编辑后重建语法树,我们可以重新使用许多现有的一成不变的解析树从以前的文本。我们始终遍历从上而下的树,只希望在必要时计算父引用。

We use this latter approach in the C# and VB compilers because that is precisely the situation we are in: when we rebuild a parse tree after a code edit we can re-use much of the existing immutable parse tree from the previous text. We always traverse the tree from the top down, and only want to compute the parent references when necessary.

这篇关于在C#4.0中,有没有什么办法能让一个可用类的,否则私有成员只对特定的其他类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆