инкапсуляция и дружба в C # - PullRequest
0 голосов
/ 30 апреля 2011

У меня есть конкретный случай в моем текущем проекте.

У меня есть:

public class A
{
   // etc.
}

public class B
{
   // etc.

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

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

Я хочу:

  1. A чтобы иметь возможность вызывать закрытый метод B.HandleSomeEvent, но нет другого класса (кроме B), чтобы это можно было сделать
  2. A чтобы иметь возможность вызывать защищенный метод B.HandleSomeOtherEvent, но нет другого класса (кроме производных классов B и B), чтобы это можно было сделать

Возможно ли это в C #?

  1. Если возможно, как это сделать?
  2. Если это невозможно, каковы альтернативы, которые могут максимально защитить B от взлома, скажем, класса C в той же сборке?

Ответы [ 6 ]

1 голос
/ 21 июня 2012

Это возможно путем создания интерфейса A и последующего отделения его от конкретной реализации. Как только вы это сделали, вы можете написать что-то вроде этого

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) { }
}

Несмотря на то, что HandleSomeEvent() является публичной, только A может получить к ней доступ, поскольку никто другой не может получить конкретный экземпляр класса A. Он имеет приватный конструктор, а фабричный метод New() возвращает интерфейс.

Подробнее см. Мою статью Друзья и внутренние участники интерфейса с кодированием для интерфейсов .

1 голос
/ 02 мая 2011

"2. Если это невозможно, какие существуют альтернативы, которые могут максимально защитить B от, скажем, класса C в той же сборке?"звонящий и выбрасывающий исключение работает?

      [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 голос
/ 30 апреля 2011

Это возможно, но я бы просто пошел с internal и предположил, что другие классы в сборке ведут себя хорошо.

Вы можете, например, передать делегаты этим методам в класс А, который хранитих в protected static полях / свойствах.

1 голос
/ 30 апреля 2011

Возможно ли это в C #?

Нет, если вы не используете отражение: закрытые и защищенные члены не доступны из других классов.

Если это невозможно, каковы альтернативы, которые могут максимально защитить B от взлома, скажем, класса C в той же сборке?

Вы можете сделать B вложенным классом внутри A и сделать его закрытым. Затем вы можете безопасно увеличить видимость двух методов B, так как только A сможет вызывать их (если не используется отражение).

0 голосов
/ 30 апреля 2011

Вы можете пометить оба метода как internal:

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

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

Это делает эти два метода видимыми для всех классов в одной сборке (а также второй метод видимым для всех классов, производных от B).

Нет способа сделать метод видимым для определенного другого класса.В конце концов, вы тот, кто контролирует все классы в вашей сборке, поэтому вы должны убедиться, что никакой другой класс, кроме A, не вызывает методы.

Если вам действительно нужна помощь из инструментапри этом вы могли бы написать правило FxCop или создать какое-то пост-построенное действие, которое проверяет вызовы методов из других классов, отличных от A.

0 голосов
/ 30 апреля 2011
  1. Нет, это не так (если вы не используете отражение, но это просто плохой дизайн)
  2. Наследование.Но даже тогда вы не сможете вызвать приватный метод.Вы должны подумать о своем дизайне и улучшить его.

Поскольку ваш класс A должен иметь возможность вызывать protected методы для B, я полагаю, что у него есть какие-то отношения с ним.Спросите себя, существует ли отношение «есть», как в «А - это В».В этом случае вы можете A наследовать от B:

public class A : B
{
}

Теперь вы можете вызывать защищенные методы для B.Но, пожалуйста, не просто наследуй, всегда спрашивай себя, имеет ли наследство смысл.

...