如何在C#中模仿友谊?

时间:2015-09-15 12:33:14

标签: c# friend

我想声明(仅)A类可以访问/操作B类成员。当friend中没有C#时,如何实现这一点? / p>

2 个答案:

答案 0 :(得分:5)

  

我想宣布只有 A类可以访问/操纵 B类的某些成员。

突出显示的单词表示问题点。

首先,我假设只有A"只有A"你实际上是指"只有A级和B级"。在B类中声明的成员中的代码总是可以访问B类的所有成员,因此A类永远不会成为可以访问B成员的唯一类。

一种技术是使类A成为类B的唯一嵌套类。现在,类A和B是唯一可以访问类B的所有成员的类。但是,类A可以访问所有 B班成员;这不符合您的要求,即A类只能访问B类成员的部分

另一种技术是将A类和B类都放在同一个程序集中的类中,并使程序集中的类。现在你可以将你想要被A访问的B的成员标记为" internal",只有A类才能访问它们,因为它是程序集中唯一的其他类。

可能这些技术都不是你想要的。 C#并不是为了拥有这个朋友而设计的。正如你所注意到的,C ++的特性。我的建议是让你想要从A访问的B成员是内部成员。这使得当前程序集中的所有类型都可以访问它们,这是由少数人编写的少数类型,所有人都知道。你可以简单地要求他们不要使用B类,如果你有一些好的,有商业影响的理由来强加这个要求。

C#类型系统的设计并不能代表和执行同事之间的所有可能关系; " B级可以被A级使用,因为我相信Albert,但是我不想要在C级工作的Carol能够重复使用我的工作"这根本不是C#团队认为有价值的功能,可以添加到类型系统中。如果您对卡罗尔使用B级有疑虑,请与卡罗尔谈谈。

答案 1 :(得分:4)

其中一种可能性如下(希望它能为某人节省一些思考)。这适用于:

的人
  • 不喜欢(不想使用)internalInternalsVisibleToAttribute
  • 不喜欢(不想使用)反思来提取和利用" internals"。

说明

  • 让班级AB处理一些允许A操纵"内部" B
  • B定义实现此协议的非公开方法(类似于标准接口实现,但使用private / protected方法 - 禁止标准使用interface实现)。
  • B创建一个专用对象,其中包含初始化为此协议成员的代理(有效地导出所选的"内部")。
  • 将此对象从B传递到A(理想情况下无需任何用户干预),以授予A操纵B的权利。
  • A中使用它,有效地允许B愿意提供的内容。

优点:

  • B中任何意外不需要的更改空间的空间较小(与案例相反的是internalpublic)。
  • 精确控制AB可以完成的工作。

缺点:

  • 稍微复杂一点(协议定义,需要协议传递过程)。
  • A仍然提供公共基础设施方法(注册),不正当地称之为可能会造成一些伤害。

寻求代码的示例:

  • A是能够修理手机的技术人员
  • B是智能手机,提供标准(public)功能,以及进行基本维修的一些专业知识。
  • 用户可以使用标准功能,Technician(作为SmartPhone's friend)可以使用高级功能。

    /*
     * SmartPhone<-Technician friendship contract
     */
    public class SmartPhoneServiceActivities
    {
        public delegate bool ReplaceGlassHandler  (SmartPhone device);
        public delegate bool ReplaceDisplayHandler(SmartPhone device);
    
        public ReplaceGlassHandler   ReplaceGlass {get;}
        public ReplaceDisplayHandler FactoryReset {get;}
    
        public SmartPhoneServiceActivities(ReplaceGlassHandler replaceGlass, ReplaceDisplayHandler factoryReset)
        {
            ReplaceGlass = replaceGlass;
            FactoryReset = factoryReset;
        }
    }
    
    //-------------------------------------------------------------------------------
    
    public class SmartPhone
    {
        #region Friend functions
        /*
         * Provide private functions for "trusted" classes
         */
        static SmartPhone()
        {
            var services = new SmartPhoneServiceActivities(ReplaceGlass, FactoryReset); // SmartPhone<-Technician agreement regarding "private modifications"
    
            Technician.RegisterDeviceForRepair(typeof(SmartPhone), services);
        }
    
        protected static bool ReplaceGlass(SmartPhone device)
        {
            device.IsDamagedGlass = false;
            return true; // Skilled technicians only ;)
        }
    
        protected static bool FactoryReset(SmartPhone device)
        {
            device.IsDamagedSoftware = false;
            return true;
        }
        #endregion
    
    
    
        #region Standard public usage
        public bool IsDamaged => IsDamagedGlass || IsDamagedSoftware;
        public bool IsDamagedGlass    {get; protected set;}
        public bool IsDamagedSoftware {get; protected set;}
    
        public void Call() {}
    
        public void DropIt()
        {
            var isBroken = (new Random((int)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds)).Next() & 3;
    
            IsDamagedGlass    = (isBroken & 1) != 0;
            IsDamagedSoftware = (isBroken & 2) != 0;
        }
        #endregion
    }
    
    // --------------------------------------------------------------------------------
    
    public class Technician
    {
        protected static readonly Dictionary<Type, SmartPhoneServiceActivities> knowHow = new Dictionary<Type, SmartPhoneServiceActivities>();
    
        /*
         * Although this is public and improper call might cause inability of a class to register it's acceptable "risk". 
         * It's intended for static constructors invocation.
         */
        public static void RegisterDeviceForRepair(Type deviceType, SmartPhoneServiceActivities services)
        {
            if (   (!knowHow.ContainsKey(deviceType))
                && (services != null))
            {
                knowHow[deviceType] = services;
            }
        }
    
        public bool Repair(SmartPhone device)
        {
            var isRepaired = false;
            var deviceType = device.GetType();
    
            if (knowHow.ContainsKey(deviceType))
            {
                var services  = knowHow[deviceType];
                var isSoftOk  = !device.IsDamagedSoftware || services.FactoryReset(device);
                var isGlassOk = !device.IsDamagedGlass    || services.ReplaceGlass(device);
    
                isRepaired = isSoftOk && isGlassOk;
            }
    
            return isRepaired; 
        }
    }