C#中“friend”关键字的等效语句是什么?

23

'friend' 在 C# 中的等价关键字是什么?

如何使用 'internal' 关键字?

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

我在我的 C# 项目中使用了一个 DLL,我拥有它的源代码,但我不想修改现有的代码。我继承了该类并可以按任何方式使用我的派生类。问题是父类中的大部分代码都有受保护的方法。使用 'friend' 关键字是否会使访问或调用这些受保护的方法变得可能?


5
请澄清这个问题,因为VB和C都有友元关键字。而在C#中没有对应于C的友元关键字。 - Sam Saffron
可能是What is the C# equivalent of friend?的重复问题。 - phuclv
7个回答

38
  1. 你可以使用关键字访问修饰符 internal 来将类型或类型成员声明为仅对同一程序集中的代码可访问。

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

你使用第一个访问修饰符就像使用其他任何访问修饰符(如private)一样。例如:

internal class MyClass {
    ...
}
你可以按照以下方式使用第二个:
[assembly:InternalsVisibleTo("MyFriendAssembly", PublicKey="...")]
internal class MyVisibleClass {
    ...
}

这两者都可以被认为是C#中friend的等价物。

protected标识的方法已经可以被派生类访问。


37

不,"internal"和"C++的friend"并不相同。

"friend"表示该类仅可被一个特定类访问。
"internal"表示该类可以被程序集中的任何类访问。


1
这并不等同于,但它确实是一组类协同工作的机制,而不会向外部暴露自己。它还鼓励更小的模块,并减少类之间的“意大利面条式”关系。 - Dave Cousineau

7
  1. internal is the C# equivalent of the VB.NET friend keyword, as you have guessed (as opposed to a replacement)

  2. Usage is as follows

    internal void Function() {}
    internal Class Classname() {}
    internal int myInt;
    internal int MyProperty { get; set; }
    
  3. It, basically, is an access modifier that stipulates that the accessibility of the class / function / variable / property marked as internal is as if it were public to the Assembly it is compiled in, and private to any other assemblies


1
这是我用来添加类似于C++中的friend关键字行为的奇怪技巧。 据我所知,这仅适用于嵌套类。
  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
    }
}


我认为这仅适用于嵌套类。如果您想对普通类执行此操作,则需要将它们嵌套在部分外部类中,理论上应该可以工作,并使用受保护的或私有的嵌套接口(如果您倾向于使用两个)来提供对彼此私有成员的访问...但这样说不太恰当。

1

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

你想要将这些受保护成员授权给另一个类吗?


0
将一个大类分成两个部分类文件可以实现所需的友元效果。虽然不完全等同,但在某些情况下是可行的。

0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接