【问题标题】:What is the equivalent of a 'friend' keyword in C Sharp?C Sharp 中的“朋友”关键字相当于什么?
【发布时间】:2010-10-01 12:33:27
【问题描述】:

什么是 C Sharp 中的“朋友”关键字?

如何使用“内部”关键字?

我读到'internal' 关键字是 C# 中'friend' 的替代品。

我在我的 C# 项目中使用了一个 DLL,我有它的源代码,但我不想修改现有代码。我继承了这个类,我可以以任何我想要的方式使用我继承的类。问题是父类中的大部分代码都有受保护的方法。使用朋友是否可以访问或调用这些受保护的方法?

【问题讨论】:

标签: c# friend internal friend-class


【解决方案1】:
  1. internal 是 VB.NET friend 关键字的 C# 等效项,正如您所猜到的(而不是替代)

  2. 用法如下

    internal void Function() {}
    internal Class Classname() {}
    internal int myInt;
    internal int MyProperty { get; set; }
    
  3. 它基本上是一个访问修饰符,它规定标记为内部的类/函数/变量/属性的可访问性就好像它对编译它的程序集是公共的,对任何其他组件

【讨论】:

    【解决方案2】:

    内部相当于朋友。受保护的方法只能在同一个类中或从继承者中使用。如果您尝试从继承者公开受保护的方法,您可以将它们包装在公共方法中。

    【讨论】:

      【解决方案3】:

      您的子类将能够访问您继承的类的受保护成员。

      您是否希望将这些受保护成员的访问权限授予另一个类?

      【讨论】:

        【解决方案4】:
        1. 您可以使用关键字访问修饰符internal 将类型或类型成员声明为仅对同一程序集中的代码可访问。

        2. 您可以使用System.Rutime.CompilerServices 中定义的InternalsVisibleToAttribute 类来声明一个类型可被同一程序集中的代码或仅指定程序集中的代码访问。

        您使用第一个就像使用任何其他 access modifier(例如 private)一样。也就是说:

        internal class MyClass {
            ...
        }
        

        你使用第二个如下:

        [assembly:InternalsVisibleTo("MyFriendAssembly", PublicKey="...")]
        internal class MyVisibleClass {
            ...
        }
        

        这两者都可以正确地被认为等同于 C# 中的friend

        protected 的方法已经可用于派生类。

        【讨论】:

          【解决方案5】:

          不,“内部”与“朋友”不同(至少是 C++ 的“朋友”)

          friend 指定该类只能由 ONE 特定类访问。
          internal 指定该类可由程序集中的任何类访问。

          【讨论】:

          • 它不是等价的,但它一种机制,通过该机制一组类可以协同工作,而不会将自己暴露给世界其他地方。它还鼓励使用更小的模块并减少类之间的“意大利面条”关系。
          【解决方案6】:

          这是我用来添加类似于 C++ 的 friend 关键字的行为的一个奇怪技巧。 这仅适用于嵌套类 AFAIK。

          1. 创建一个嵌套的protectedprivate 接口,其中包含您希望通过属性访问的变量。
          2. 让嵌套类继承这个接口并显式地实现
          3. 每当使用此嵌套类的对象时,将其强制转换为接口并调用相应的属性。

          这是一个来自 Unity 的示例。

          using System;
          using UnityEngine;
          using UnityEngine.Assertions;
          
          namespace TL7.Stats
          {
              [CreateAssetMenu(fileName = "Progression", menuName = "TL7/Stats/New Progression", order = 0)]
              public class Progression : ScriptableObject
              {
                  // Provides access to private members only to outer class Progression
                  protected interface IProgressionClassAccess
                  {
                      CharacterClass CharacterClass { get; set; }
                  }
          
                  [System.Serializable]
                  public struct ProgressionClass : IProgressionClassAccess
                  {
                      [Header("DO NOT EDIT THIS VALUE.")]
                      [SerializeField] private CharacterClass characterClass;
                      [Tooltip("Levels are 0 indexed.")]
                      [SerializeField] float[] healthOverLevels;
          
                      public float[] HealthOverLevels => healthOverLevels;
          
                      CharacterClass IProgressionClassAccess.CharacterClass
                      {
                          get => characterClass;
                          set => characterClass = value;
                      }
                  }
          
                  static readonly Array characterClasses = Enum.GetValues(typeof(CharacterClass));
                  [SerializeField] ProgressionClass[] classes = new ProgressionClass[characterClasses.Length];
          
                  public ProgressionClass this[in CharacterClass index] => classes[(int)index];
          
                  void Awake()
                  {
                      for (int i = 0; i < classes.Length; ++i)
                      {
                          // Needs to be cast to obtain access
                          (classes[i] as IProgressionClassAccess).CharacterClass = (CharacterClass)characterClasses.GetValue(i);
                      }
                  }
          
          #if UNITY_EDITOR
                  public void AssertCorrectSetup()
                  {
                      for (int i = 0; i < characterClasses.Length; ++i)
                      {
                          CharacterClass characterClass = (CharacterClass)characterClasses.GetValue(i);
                          Assert.IsTrue(
                              (this[characterClass] as IProgressionClassAccess).CharacterClass == characterClass,
                              $"You messed with the class values in {GetType()} '{name}'. This won't do."
                          );
                      }
                  }
          #endif
              }
          }
          
          

          我认为这只适用于嵌套类。如果您想对常规类执行此操作,则需要将它们嵌套在部分外部类中,这在理论上应该可以工作,并使用 protectedprivate 嵌套接口(或两个,如果你倾向于)为他们提供访问彼此私人信息的权限……结果是错误的。

          【讨论】:

            【解决方案7】:

            将一个大类拆分为两个部分类文件可以实现所需的朋友效应。它不是等效的,但在某些情况下有效。

            【讨论】:

              猜你喜欢
              • 2013-10-08
              • 1970-01-01
              • 1970-01-01
              • 2010-12-10
              • 2011-05-08
              • 2013-03-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多