c++的friend关键字允许类a将类B指定为它的friend。这允许类B访问类A的私有/受保护成员。

我从来没有读过任何关于为什么c#(和VB.NET)中不包含这个的东西。大多数关于StackOverflow问题的答案似乎都在说它是c++的一个有用的部分,并且有很好的理由使用它。以我的经验,我不得不同意。

对我来说,另一个问题似乎是在问如何在c#应用程序中做类似于friend的事情。虽然答案通常围绕嵌套类,但它似乎没有使用friend关键字那么优雅。

最初的《设计模式》一书在其示例中经常使用它。

总之,为什么在c#中没有friend,在c#中模拟friend的“最佳实践”方法是什么?

(顺便说一下,internal关键字不是一回事,它允许整个程序集中的所有类访问内部成员,而friend允许你给某个类完全访问另一个类)


当前回答

c#缺少“friend”关键字的原因与缺少确定性销毁的原因相同。改变传统让人们觉得自己很聪明,好像他们的新方式比别人的旧方式更优越。这都是关于骄傲。

说“朋友类不好”就像“不要用gotos”或“Linux比Windows好”一样是短视的。

“friend”关键字与代理类相结合是只向特定的其他类公开类的某些部分的好方法。代理类可以作为对所有其他类的可信屏障。“public”不允许任何这样的目标,如果真的没有概念上的“is a”关系,使用“protected”来获得继承的效果是很尴尬的。

其他回答

你可以用c#关键字“internal”来接近c++的“朋友”。

我读过许多关于“朋友”关键字的聪明评论,我同意它是有用的东西,但我认为“内部”关键字没有那么有用,而且它们对纯OO编程来说都很糟糕。

我们有什么?(说到“朋友”,我也说到“内部”)

使用“friend”是否会使代码对于oo不那么纯粹? 是的, 不使用“friend”会使代码更好吗? 不,我们仍然需要在类之间建立一些私人关系,而且只有打破了我们美丽的封装才能做到,所以这也不好,我可以说它比使用“朋友”更邪恶。

使用friend会产生一些局部问题,不使用friend会给代码库用户带来问题。

在我看来,编程语言的通用解决方案是这样的:

// c++ style
class Foo {
  public_for Bar:
    void addBar(Bar *bar) { }
  public:
  private:
  protected:
};

// c#
class Foo {
    public_for Bar void addBar(Bar bar) { }
}

你觉得怎么样?我认为这是最常见的纯面向对象的解决方案。你可以对你想要的任何类打开任何方法的访问。

这种友谊可以通过分离接口和实现来模拟。其思想是:“需要一个具体实例,但限制该实例的构造访问”。

例如

interface IFriend { }

class Friend : IFriend
{
    public static IFriend New() { return new Friend(); }
    private Friend() { }

    private void CallTheBody() 
    {  
        var body = new Body();
        body.ItsMeYourFriend(this);
    }
}

class Body
{ 
    public void ItsMeYourFriend(Friend onlyAccess) { }
}

尽管ItsMeYourFriend()是公共的,但只有Friend类可以访问它,因为其他人不可能获得Friend类的具体实例。它有一个私有构造函数,而工厂New()方法返回一个接口。

有关详细信息,请参阅我的文章《朋友和内部接口成员,免费为接口编码》。

不要再为这种限制找借口了。朋友是坏的,但内在是好的?它们是一样的东西,只是那个朋友让你更精确地控制谁可以访问谁不能访问。

这是强制封装范式吗?所以你必须写访问器方法,然后呢?你应该如何阻止所有人(除了类B的方法)调用这些方法?你不能,因为你也控制不了,因为你失去了“朋友”。

No programming language is perfect. C# is one of the best languages I've seen, but making silly excuses for missing features doesn't help anyone. In C++, I miss the easy event/delegate system, reflection (+automatic de/serialization) and foreach, but in C# I miss operator overloading (yeah, keep telling me that you didn't need it), default parameters, a const that cannot be circumvented, multiple inheritance (yeah, keep telling me that you didn't need it and interfaces were a sufficient replacement) and the ability to decide to delete an instance from memory (no, this is not horribly bad unless you are a tinkerer)

B.s.d。

有人说,朋友伤害纯粹的孤独。我同意这一点。

还有人说,朋友会帮助封装,我也同意这一点。

我认为友谊应该添加到OO方法中,但不像在c++中那样。我想有一些字段/方法,我的朋友类可以访问,但我不希望他们访问我所有的字段/方法。在现实生活中,我会让我的朋友们进入我的私人冰箱,但我不会让他们进入我的银行账户。

我们可以按照下面的方法实现它

    class C1
    {
        private void MyMethod(double x, int i)
        {
            // some code
        }
        // the friend class would be able to call myMethod
        public void MyMethod(FriendClass F, double x, int i)
        {
            this.MyMethod(x, i);
        }
        //my friend class wouldn't have access to this method 
        private void MyVeryPrivateMethod(string s)
        {
            // some code
        }
    }
    class FriendClass
    {
        public void SomeMethod()
        {
            C1 c = new C1();
            c.MyMethod(this, 5.5, 3);
        }
    }

这当然会生成一个编译器警告,并将损害智能感知。但它会起作用的。

另一方面,我认为一个自信的程序员应该在不访问私有成员的情况下进行测试单元。这已经超出了本文的范围,但请尝试阅读TDD。 然而,如果你仍然想这样做(有c++喜欢的朋友),尝试一些像

#if UNIT_TESTING
        public
#else
        private
#endif
            double x;

所以你写的所有代码都没有定义UNIT_TESTING,当你想要进行单元测试时,你在文件的第一行添加#define UNIT_TESTING(并在#if UNIT_TESTING下编写所有进行单元测试的代码)。这应该小心处理。

因为我认为单元测试对于朋友的使用是一个不好的例子,所以我想举一个例子来说明为什么我认为朋友可以是好的。假设你有一个破碎的系统(类)。随着使用,破碎系统磨损,需要翻新。现在,你希望只有有执照的技工才能修理它。为了让这个例子不那么琐碎,我想说机械师会用他的私人螺丝刀来修理它。这就是为什么机制类应该是breakingSystem类的朋友。