21

C Sharp 中的“朋友”关键字相当于什么?

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

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

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

4

7 回答 7

35
  1. 您可以使用关键字访问修饰符internal将类型或类型成员声明为只能由同一程序集中的代码访问。

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

您使用第一个,因为您使用任何其他访问修饰符,例如private. 以机智:

internal class MyClass {
    ...
}

您使用第二个如下:

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

这两者都可以正确地视为friendC# 中的等价物。

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

于 2009-01-15T03:15:18.600 回答
33

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

朋友指定这个类只能由一个特定的类访问。
internal 指定该类可由程序集中的任何类访问。

于 2010-11-13T17:00:18.207 回答
6
  1. internal正如您所猜测的那样,是 VB.NET 关键字的 C# 等效项friend(而不是替换)

  2. 用法如下

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

于 2009-01-15T03:07:40.813 回答
1

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

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

于 2009-01-15T03:08:43.790 回答
1

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

  1. 使用您希望通过属性访问的变量创建嵌套protected或接口。private
  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嵌套接口(或两个,如果您愿意)为它们提供访问权限对彼此的私人... 出来错了。

于 2019-07-25T11:30:07.957 回答
0

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

于 2009-01-15T03:07:48.723 回答
0

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

于 2020-05-02T11:39:10.707 回答