如何确保一个类可以在另一个类上调用一个方法,而不是其他类可以调用该方法

本文关键字:调用 方法 一个 其他 确保 另一个 何确保 | 更新日期: 2023-09-27 18:29:31

我有两个类要保存在不同的文件中。

namespace GridSystem
{
    public class Grid
    {
        public void AddItem(GridItem item)
        {
            item.InformAddedToGrid();
        }
    }
}
namespace GridSystem
{
    public class GridItem
    {
        public void InformAddedToGrid()
        {
            Debug.Log("I've been added to the grid");
        }
    }
}

如何确保不允许其他类调用InformAddedToGrid?

我正在尝试模拟Actionscript命名空间,它可以在方法上使用,而不是公共、私有、内部等。它并不能完全保护方法,但在访问方法之前,强制执行额外的步骤,包括命名空间。在C#中有没有其他方法可以替代?

如何确保一个类可以在另一个类上调用一个方法,而不是其他类可以调用该方法

如果GridItem本身也可以对外部世界隐藏,我会考虑将GridItem作为嵌套类放入Grid中。这样它就不会在类之外可见

http://www.codeproject.com/Articles/20628/A-Tutorial-on-Nested-Classes-in-C

不是说你应该这样做,你应该按照TGH的建议,为GridItem提供一个公共接口,并在Grid中嵌套GridItem(然后在Grid上有一个工厂方法来创建Item,并使用部分Grid类将它们放在单独的文件中)。

因为没有一种方法可以拥有friend方法(可以通过InternalsVisibleToAttribute进行friend类)

可以这样做(但不要…)

public partial class Grid
{
   public void AddItem(GridItem item)
   {
      item.InformAddedToGrid();
   }
}        
public class GridItem
{
   public void InformAddedToGrid()
   {                
      if (new StackTrace().GetFrame(1).GetMethod().DeclaringType != 
                   typeof(Grid)) throw new Exception("Tantrum!");
      Console.WriteLine("Grid called in...");
   }
}

然后

 var g = new Grid();
 g.AddItem(new GridItem()); // works
 new GridItem().InformAddedToGrid(); // throws a tantrum...

一个非常丑陋的答案是将其私有化并使用反射。

另一个丑陋的答案是,如果调用者错了,让它抛出一个异常。

这两种方法的执行速度也比普通调用慢得多。

我认为没有一个好的答案。C#没有朋友。

IMHO答案很简单:访问修饰符只是用来提醒程序员的意图类应该是公共/私有的。通过反思,你可以消除这些障碍。

类的用法完全掌握在你的手中:如果你的类意味着只能在一个地方使用,那么就这样做。如果有什么不同的话,如果一个类有一种特殊的使用方式,那么就把它记录下来——放在XML注释中。

也就是说,在这个特定的例子中,我相信由于GridItem没有将自己添加到网格中,它的工作不是通知它(如果"我还没有被添加到网格"怎么办?)。我认为InformAddedToGrid作为private方法属于Grid类的某个地方,其中有一个添加项的概念。。。假设CCD_ 6确实是这么做的。

您可以按照TGH的建议,使用嵌套类来完成这项工作,但方法不同。将Grid嵌套在GridItem中,并将InformAddedToGrid设为私有。这里我使用了一个嵌套的基类,这样公共的API就可以保持不变。请注意,程序集之外的任何人都不能从GridBase继承,因为构造函数是内部的。

public class GridItem
{
    public class GridBase
    {
        internal GridBase() { }
        public void AddItem(GridItem item)
        {
            item.InformAddedToGrid();
        }
    }
    private void InformAddedToGrid()
    {
        Debug.Log("I've been added to the grid");
    }
}
public class Grid : GridItem.GridBase { }

另一种选择是让GridItem显式地实现一个内部接口。这样,程序集之外的任何人都不能按名称使用接口,因此不能调用InformAddedToGrid

public class Grid
{
    public void AddItem(GridItem item)
    {
        ((IGridInformer)item).InformAddedToGrid();
    }
}
public class GridItem : IGridInformer
{
    void IGridInformer.InformAddedToGrid()
    {
        Debug.Log("I've been added to the grid");
    }
}
internal interface IGridInformer
{
    void InformAddedToGrid();
}