Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何确保一个类可以调用另一个类上的方法,但其他类不能调用该方法?_C# - Fatal编程技术网

C# 如何确保一个类可以调用另一个类上的方法,但其他类不能调用该方法?

C# 如何确保一个类可以调用另一个类上的方法,但其他类不能调用该方法?,c#,C#,我有两个类,我想保存在单独的文件中 namespace GridSystem { public class Grid { public void AddItem(GridItem item) { item.InformAddedToGrid(); } } } namespace GridSystem { public class GridItem { public v

我有两个类,我想保存在单独的文件中

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本身可以被隐藏在外部世界,那么我会考虑把网格中的GrIDItIn作为嵌套类来放置。这样,它就不会在课堂外可见


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

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

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


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

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

因为没有一种方法可以拥有friend方法(您可以通过
InternalsVisibleToAttribute
创建friend类)

你可以这样做(但不要…)

然后


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

你对一个类的使用完全掌握在你的手中:如果你的类只打算在一个地方使用,那么就这样做吧。如果有的话,如果一个类有一种特殊的使用方式,那么记录它——将它放在XML注释中


也就是说,在这个具体的例子中,我相信既然
GridItem
没有将自己添加到网格中,那么通知它就不是它的工作了(如果“我没有添加到网格中怎么办?”)。我认为
InformAddedToGrid
作为
private
方法属于
Grid
类中的某个地方,其中有一个添加项的概念。。。假设这就是AddItem(GridItem)真正的功能。

您可以按照TGH的建议,使用嵌套类来实现,但另一种方式除外。在
GridItem
中嵌套
Grid
,并将
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();
}

将其更改为<代码>私下<代码>方法。看起来你在寻找C++的代码等价于C++ <代码>朋友< />代码。我不认为它存在。当它是私有网格时,也不能访问它。@神秘的是它不存在。最近的事情是
internal
。根据他在网格上的API,他有向外部世界公开GridItem的概念,这很有意义,我会在GridItem上放置一个未定义方法的接口,然后将其公开给外部世界。通过这种方式,您可以将需要从原始GridItem类中公开的内容公开给外部世界,但出于好奇,仍然隐藏了该方法。您是说通常不使用
部分
,还是说当您说
但不…,
时,您只是参考了整个示例?方法内联会让您步履维艰像那样堆叠。这样一个方法的性能将会非常糟糕。所以您指的是如果(new StackTrace().GetFrame(1.GetMethod().DeclaringType!=typeof(Grid))抛出新异常(“Tantrum!”)
作为一个坏主意?@jmstoker是的,我说的是找出调用类型,坏主意,但只是把它放在那里,以防万一它对某一天偶然遇到的人有用。我实际上喜欢这个答案,因为我可以将StackTrace检查包装在一个条件编译器指令中。我只想提醒我的开发伙伴,如果他们不正确地使用这些类,假设他们没有RTFM。在发布产品中,我不需要执行此检查。这也使类保持了良好的独立性。谢谢。即使InformAddedToGrid是Grid的成员,GridItem仍然会有我想要为GridSystem命名空间中的类保留的公共访问器。例如,InformAddedToGrid可能会修改GridItem的X和Y值。我只希望GridSystem类能够写入X和Y值,GridSystem之外的类只能读取X和Y值。在访问方面,我通常是python式的,但我希望在这个特殊的情况下更简单一些(这就是我问这个问题的原因)。
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 { }
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();
}