Можно ли вызывать функцию только из другой функции? - PullRequest
1 голос
/ 27 февраля 2009

В C # возможно ли создать функцию, которую можно вызывать только из другой функции?

Например, вы можете сделать что-то подобное?

private void a()
{


b();
c();
...do something else

private void b()
{
  ..do something but can only be called from a()
}

private void c()
{
  ..do something but can only be called from a()
}

}

Причина, по которой я хочу это сделать, заключается в том, что функции b() и c() разделяют некоторые детали внедрения на a(), и они просто чище и их легче читать в их собственном объеме. Однако эти функции бесполезны для класса, так как a() выполняет некоторую обработку после их вызова, что должно произойти.

Ответы [ 12 ]

10 голосов
/ 27 февраля 2009

Возможно использовать анонимную вложенную функцию?

9 голосов
/ 27 февраля 2009

Я бы не стал беспокоиться о том, чтобы предпринять явные шаги для того, чтобы b() и c() вызывались только по a().

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

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

Кроме того, для будущих сопровождающих вашего кода простой комментарий, такой как:

//this method should only be called by a()
private void b()
{
    ...
}

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

6 голосов
/ 27 февраля 2009

Используя делегата, вы можете сделать:

public voidMyFunction()
{

   Func<string> myFunction=(s)=>Console.WriteLine(s);

   foreach(string str in myStringList)
   {
      myFunction(str);
   }
}
2 голосов
/ 27 февраля 2009

Вы можете использовать класс StackFrame, чтобы проверить во время выполнения, кто вызывает функцию:

public class MyClass
{
    public static void A()
    {
       B();
    }

    public static void B()
    {
        var stackTrace = new StackTrace();

        if (stackTrace.FrameCount < 1 || stackTrace.GetFrame(1).GetMethod() != typeof(MyClass).GetMethod("A"))
              throw new InvalidOperationException("Not called from A()");
    }
}

Но это

1) Только во время выполнения

2) Медленный

3) Очень грязный хак

2 голосов
/ 27 февраля 2009

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

http://www.csharp -examples.net /-вызова-метод имя отражения /

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

Я бы просто задокументировал намерение в заголовках / комментариях метода.

Подобный вопрос здесь - обратите внимание на комментарии к ответу

2 голосов
/ 27 февраля 2009

Краткий ответ - нет; однако вы можете создать анонимный делегат или лямбда-выражение в качестве внутреннего метода b ().

0 голосов
/ 27 февраля 2009

Может быть проще использовать #region в этом случае

0 голосов
/ 27 февраля 2009

Я не знаю, но, возможно, может помочь Code by Contracts, но это не поддерживается изначально

0 голосов
/ 27 февраля 2009

Вы также можете создать что-то вроде этого:

internal abstract class SecretFunctionWrapper
{
    private void MySecretFunction()
    {
        ...
    }

    protected void FunctionWhichCalls()
    {
        ...
        MySecretFunction();
    }
}

public MyRealClass : SecretFunctionWrapper
{
    ...
}

Это будет работать только для одной функции. Вы также можете попробовать вложенный закрытый класс, например так:

public class A
{
    private static class Wrapped
    {
        private static void A()
        {
            secred code
        }

        public static void B()
        {
            A();
        }
    }

    public void UsingA()
    {
        Wrapped.B();
    }
}
0 голосов
/ 27 февраля 2009

Чтобы получить эффект только a (), вызывающего b (), либо сделайте, как уже заметил Эндрю, поместив a () и b () в класс и пометив b () соответствующим образом. Если вы работаете внутри полностью управляемой сборки, вы можете использовать internal вместо private, если a () и b () будут в разных классах, но в одной сборке. Тогда пользовательский код не сможет вызвать его (из-за пределов вашей сборки, то есть из их прикладной программы), и вы сможете контролировать с помощью политики запись вашей сборки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...