Подтвердить что ты не робот

Метод предела, который должен быть вызван только определенным классом

Я хочу, чтобы конкретный метод в одном классе мог быть доступен только определенному классу. Например:

public class A
{
  public void LimitedAccess() {}
  public void FullAccess() {}
}

public class B
{
  public void Func()
  {
     A a = new A();
     a.LimitedAccess();       // want to be able to call this only from class B
  }
} 

public class C
{
  public void Func()
  {
     A a = new A();
     a.FullAccess();           // want to be able to call this method
     a.LimitedAccess();        // but want this to fail compile
  }
} 

Есть ли ключевое слово или атрибут, которые я могу использовать для обеспечения этого?

UPDATE:

В связи с существующей сложностью системы и временными ограничениями мне понадобилось решение с низким уровнем воздействия. И я хотел, чтобы во время компиляции указывалось, что функция LimitedAccess() не может быть использована. Я надеюсь, что Джон Скит ответит, что именно то, что я просил, не может быть сделано на С#.

Вопрос и ответ Джона полезны тем, кто может столкнуться с этим позже. И тот факт, что этот дизайн пахнет, может надеяться, убедит кого-нибудь в том, что он выбрал что-то подобное в качестве желаемого решения.

Как упоминалось в комментарии, разговор С# friend полезен, если вы пытаетесь решить подобную ситуацию.

Что касается моего конкретного решения: "зачем A содержать B-логику" (задается @sysexpand в комментариях). Что руб. B.Func() был вызван во всей системе, над которой я работаю, но в основном работал на одноэлементном режиме A. Так что я закончил делать, двигая B Func() в A и делая A.LimitedAccess() частным. Было несколько других деталей для работы, как всегда, но я получил решение с низким уровнем воздействия, которое давало мне ошибки времени компиляции для вызывающих абонентов на A.LimitedAccess().

Спасибо за обсуждение.

4b9b3361

Ответ 1

Нет. Единственное, что вы могли бы сделать, это сделать LimitedAccess приватный метод и вложить класс B в класс A.

(Я предполагаю, что вы хотите, чтобы все классы в одной и той же сборке. В противном случае вы могли бы поставить A и B в одну сборку и C в другую сборку и сделать LimitedAccess a internal.)

Ответ 2

Предполагая, что вы хотите ограничить доступ к методам и переменным только для конкретного экземпляра, вы можете добиться этого эффекта с помощью интерфейса. Однако это не мешает кому-либо создавать свой собственный экземпляр класса, и в этот момент у него будет полный доступ к этому экземпляру.

public interface IA
{
  void FullAccess();
}


public class A : IA
{
  public void LimitedAccess() {}  //does not implement any interface
  public void FullAccess() {}     //implements interface
}


public class B
{
  private A a = new A();

  public IA GetA()
  {
    return (IA)a;
  }

  public void Func()
  {
     /* will be able to call LimitedAccess only from class B, 
        as long as everybody else only has a reference to the interface (IA). */
     a.LimitedAccess();       
  }
} 


//This represents all other classes
public class C
{
  public IA Ia;

  public void Func()
  {
     Ia.FullAccess();           // will be able to call this method
     Ia.LimitedAccess();        // this will fail compile
  }
} 

public static class MainClass
{
  static void Main(string[] args)
  {
    B b = new B();
    b.Func();
    C c = new C();
    c.Ia = b.GetA();
    c.Func();
  }
}

Ответ 3

Возможно, это обходное решение.

Используйте System.Runtime.CompilerServices, а затем вы можете проверить имя вызывающей функции и/или файл, в котором определена вызывающая функция. Если у вас есть класс для файла, имя файла может быть подстрокой для имени класса. Проверьте его и заблокируйте вызов.

internal void MySecretFunction (string something,
  [CallerMemberName] string memberName = null,
  [CallerFilePath] string filePath = null,
  [CallerLineNumber] int lineNumber = 0) {
    if (!filePath.EndsWith(@"\goodClass.cs")) return;

    // else do something
}

Ответ 4

Это против лучших методов ООП, чтобы сделать такой проект. Методы классов не должны быть защищены от вызова.

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

Ответ 5

В случае, если вы просто хотите напомнить себе (или товарищам по команде), чтобы не вызывать LimitedAccess везде, вы можете рассмотреть возможность использования явной реализации интерфейса или пометить LimitedAccess как устаревший.

public interface IA
{
    void LimitedAccess();
    void FullAccess();
}

public class A : IA
{
    private void LimitedAccess() { }
    public void FullAccess() { }

    void IA.LimitedAccess() => LimitedAccess();
    void IA.FullAccess() => FullAccess();
}

public class B
{
    public void Func()
    {
        IA a = new A();
        a.LimitedAccess();       // want to be able to call this only from class B
    }
}

public class C
{
    public void Func()
    {
        A a = new A();
        a.FullAccess();           // want to be able to call this method
        a.LimitedAccess();        // -> fails to compile
    }
}