简体   繁体   English

C#中的封装和友谊

[英]encapsulation and friendship in C#

I have a particular case in my current project.我目前的项目中有一个特殊案例。

I have:我有:

public class A
{
   // etc.
}

public class B
{
   // etc.

   private void HandleSomeEvent(object parameter)
   {
      // Etc.
   }

   protected void HandleSomeOtherEvent(object parameter)
   {
      // Etc.
   }
}

I want:我想:

  1. A to be able to call the private method B.HandleSomeEvent , but no other class (but B ) to be able to do that A能够调用私有方法B.HandleSomeEvent ,但没有其他 class (但B )能够做到这一点
  2. A to be able to call the protected method B.HandleSomeOtherEvent , but no other class (but B and B 's derived classes) to be able to do that A能够调用受保护的方法B.HandleSomeOtherEvent ,但没有其他 class (但BB的派生类)能够做到这一点

Is that possible in C#?在 C# 中可能吗?

  1. If possible, how to do that?如果可能,该怎么做?
  2. If not possible, what are the alternatives which can protect B as much as possible from tampering from, say, a class C in the same assembly?如果不可能,有哪些替代方案可以尽可能保护B免受同一组件中的 class C的篡改?

It is possible by emitting an interface of A then separating it from a concrete implementation.可以通过发出 A 的接口然后将其与具体实现分离。 Once you did it you can write something like this一旦你做到了,你可以写这样的东西

interface IA { }

class A : IA
{
    public static IA New() { return new A(); }
    private A() { }

    private void UseB() 
    {  
        var b = new B();
        b.HandleSomeEvent(this, null);
    }
}

class B
{ 
    public void HandleSomeEvent(A onlyAccess, object parameter) { }
}

In spite of the fact that HandleSomeEvent() is public only A can access it, since no one else can possibly get a concrete instance of A class.尽管HandleSomeEvent()是公共的,但只有 A 可以访问它,因为没有其他人可以得到 A class 的具体实例。 It has a private constructor, while the factory New() method returns an interface.它有一个私有构造函数,而工厂New()方法返回一个接口。

See my article Friends and internal interface members at no cost with coding to interfaces for details.有关详细信息,请参阅我的文章Friends and internal interface members at no cost with coding to interfaces

Is that possible in C#?在 C# 中可能吗?

No, unless you use reflection: private and protected members are not accessible from other classes.不,除非您使用反射:其他类无法访问私有成员和受保护成员。

If not possible, what are the alternatives which can protect B as much as possible from tampering from, say, a class C in the same assembly?如果不可能,有哪些替代方案可以尽可能保护 B 免受同一组件中的 class C 的篡改?

You could make B a nested class inside A and make it private.您可以将 B 设为 A 内的嵌套 class 并将其设为私有。 Then you can safely increase the visibility of the two methods of B as only A will be able to call them (unless reflection is used).然后您可以安全地增加 B 的两种方法的可见性,因为只有 A 能够调用它们(除非使用反射)。

It is possible, but I'd usually just go with internal and assume that other classes in the assembly are well behaved.这是可能的,但我通常只使用带internal的 go 并假设程序集中的其他类表现良好。

You could for example pass delegates to these methods to class A which stores them in protected static fields/properties.例如,您可以将这些方法的委托传递给 class A,后者将它们存储在protected static字段/属性中。

"2. If not possible, what are the alternatives which can protect B as much as possible from tampering from, say, a class C in the same assembly?" “2. 如果不可能,有哪些替代方案可以尽可能保护 B 免受同一组件中的 class C 的篡改?”

Would checking the type info of the caller and throwing an exception work?检查调用者的类型信息并抛出异常是否有效?

      [MethodImpl(MethodImplOptions.NoInlining)]  
      private void HandleSomeEvent(object parameter)  
      {  
            StackTrace stackTrace = new StackTrace();
            StackFrame stackFrame = stackTrace.GetFrame(1);
            MethodBase methodBase = stackFrame.GetMethod();

            if(methodBase.DeclaringType == typeof(ClassA)) // Okay.
            else if (methodBase.DeclaringType == typeof(ClassB)) // Okay.
            else throw new ApplicationException("Not Okay");
      }
  1. No, it isn't (unless you use reflection, but that's just bad design)不,不是(除非你使用反射,但这只是糟糕的设计)
  2. Inheritance. Inheritance。 But even then you won't be able to call the private method.但即便如此,您也无法调用私有方法。 You should think about your design and improve it.你应该考虑你的设计并改进它。

As your class A should be able to call protected methods on B , I figure it has some sort of relationship with it.由于您的 class A应该能够在B上调用protected的方法,我认为它与它有某种关系。 Ask yourself if there is a "is-a" relationship, as in "A is a B".问问自己是否存在“is-a”关系,例如“A is a B”。 In this case, you can make A inherit from B :在这种情况下,您可以让AB继承:

public class A : B
{
}

Now, you are able to call protected methods on B .现在,您可以在B上调用受保护的方法。 But please, don't just inherit, always ask yourself if the inheritance makes sense.但是请不要仅仅继承,要经常问自己 inheritance 是否有意义。

You can mark both methods as internal :您可以将这两种方法标记为internal

internal void HandleSomeEvent(object parameter)
{
   // Etc.
}

protected internal void HandleSomeOtherEvent(object parameter)
{
   // Etc.
}

This makes the two methods visible to all classes in the same assembly (and also the second method visible to all classes derived from B ).这使得这两种方法对同一程序集中的所有类都可见(并且第二种方法对从B派生的所有类都可见)。

There is no way to make a method visible to a specific other class.无法使方法对特定的其他 class 可见。 After all, you're the one who's controlling all classes in your assembly, so it's up to you to make sure that no other class than A calls the methods.毕竟,您是控制程序集中所有类的人,因此您需要确保除A之外没有其他 class 调用这些方法。

If you really need help from a tool with this, you could write an FxCop rule or create some kind of post-built action that checks for method calls from other classes than A .如果你真的需要这个工具的帮助,你可以编写一个 FxCop 规则或创建某种后期构建操作来检查来自A以外的其他类的方法调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM