什么是C#相当于朋友?

Ben*_*n L 175 c#

可能重复:
为什么C#不提供C++风格的'friend'关键字?

我希望类的私有成员变量可以被Tester类访问,而不会将它们暴露给其他类.

在C++中,我只是将Tester类声明为朋友,如何在C#中执行此操作?有人能举个例子吗?

Jon*_*eet 249

没有直接相当于"朋友" - 最接近的是(并且它不是非常接近)是InternalsVisibleTo.我只使用过这个属性进行测试 - 它非常方便!

示例:要放入AssemblyInfo.cs

[assembly: InternalsVisibleTo("OtherAssembly")]
Run Code Online (Sandbox Code Playgroud)

  • 有趣的是,在VB.NET中,`Internal`仍称为"朋友". (9认同)
  • @Elmue:MSDN不正确.例如,私有嵌套类型不可见.并且内部成员仅对*指定的*程序集可见 - 它不仅仅是将所有内容公开.我*远*喜欢使用这种反射,这不是重构友好或编译时检查友好. (3认同)
  • @Elmue:你让班级内部,这就是全部.是的,它比"朋友"更细粒度 - 这在某些情况下很有用,而在其他情况下则没用.就个人而言,它并没有打扰我. (3认同)

小智 74

壁橱等效于创建一个嵌套类,它将能够访问外部类的私有成员.像这样的东西:

class Outer
{
    class Inner
    {
       // This class can access Outer's private members
    }
}
Run Code Online (Sandbox Code Playgroud)

或者如果您更喜欢将Inner类放在另一个文件中:

Outer.cs
partial class Outer
{
}


Inner.cs
partial class Outer
{
    class Inner
    {
       // This class can access Outer's private members
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,为了访问外部类的成员,除非变量是静态的(或const),否则仍需要对Outer实例的引用.根据接受的答案:http://stackoverflow.com/questions/3155172/inner-class-and-outer-class-in-c-sharp (7认同)
  • 卫生署!内部类不允许使用扩展方法. (2认同)
  • 我觉得这是一个非常有趣的想法。如果我们可以排除标记“partial”关键字,那么我们就可以允许其他类(存储库、工厂等)访问我们的私有成员。更重要的是,该类被迫公开表明它正在这样做(即,将自身包装在它正在访问的类的一部分中)。 (2认同)

小智 43

采取一种非常常见的模式.Class Factory制作小部件.工厂类需要与内部进行混淆,因为它是工厂.两者都在同一个文件中实现,并且根据设计和愿望与性质,紧密耦合的类 - 事实上,Widget实际上只是工厂的输出类型.

在C++中,使Factory成为Widget类的朋友.

在C#中,我们能做什么?我遇到的唯一合适的解决方案是创建一个接口IWidget,它只公开公共方法,并让Factory返回IWidget接口.

这涉及相当多的单调乏味 - 在界面中再次暴露所有自然公共财产.

  • 这是一个很好的使用模式,但在单元测试时通常不是一个好的解决方案,因为您需要对正在测试的类的构造进行精细控制,该类应该与其他依赖项隔离。如果我的工厂将其他具体依赖项注入到我正在测试的类中,我就会陷入冲突。 (2认同)

小智 14

C#中没有'friend'关键字,但测试私有方法的一个选项是使用System.Reflection来获取方法的句柄.这将允许您调用私有方法.

给定一个具有此定义的类:

public class Class1
{
    private int CallMe()
    {
        return 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用以下代码调用它:

Class1 c = new Class1();
Type class1Type = c.GetType();
MethodInfo callMeMethod = class1Type.GetMethod("CallMe", BindingFlags.Instance | BindingFlags.NonPublic);

int result = (int)callMeMethod.Invoke(c, null);

Console.WriteLine(result);
Run Code Online (Sandbox Code Playgroud)

如果您正在使用Visual Studio Team System,那么您可以通过右键单击该方法并选择"Create Unit Tests ..."来让VS自动生成包含私有访问器的代理类.

  • @AFract - 从 .NET 4.5.1 开始,反射已被重写,不再是性能问题。4.5.1 之前的情况就是这种情况。不幸的是,CLR 团队在传达这一事实方面做得很差。尝试测试一些在 4.5.1 之前编译的繁重反射代码,并在 .NET 4.5.1+ 下重新测试相同的代码。你会看到巨大的差异。 (4认同)
  • 反射会带来沉重的性能成本,并经常导致可读性差的代码。如果可以选择的话,“部分外部类”方法对我来说要好得多。 (2认同)

小智 6

如果有权访问的类位于另一个包中,并且您公开的方法被标记为内部或内部受保护,则可以模拟朋友访问.您必须修改要共享的程序集,并将以下设置添加到AssemblyInfo.cs:

// Expose the internal members to the types in the My.Tester assembly
[assembly: InternalsVisibleTo("My.Tester, PublicKey=" +
"012700000480000094000000060200000024000052534131000400000100010091ab9" +
"ba23e07d4fb7404041ec4d81193cfa9d661e0e24bd2c03182e0e7fc75b265a092a3f8" +
"52c672895e55b95611684ea090e787497b0d11b902b1eccd9bc9ea3c9a56740ecda8e" +
"961c93c3960136eefcdf106955a4eb8fff2a97f66049cd0228854b24709c0c945b499" +
"413d29a2801a39d4c4c30bab653ebc8bf604f5840c88")]
Run Code Online (Sandbox Code Playgroud)

公钥是可选的,具体取决于您的需求.