web-dev-qa-db-fra.com

C #: Fonction dans Fonction possible?

Est-il possible de déclarer une méthode dans une autre méthode en C #?

Par exemple comme ça:

void OuterMethod()
{
    int anything = 1;
    InnedMethod();
    void InnerMethod()
    {
        int PlitschPlatsch = 2;
    }
}
62
Non

Mise à jour: fonctions locales où ajouté dans la version 7 C #.

void OuterMethod()
{
    int foo = 1;
    InnerMethod();
    void InnerMethod()
    {
        int bar = 2;
        foo += bar
    }
}

Dans la version précédente C #, vous devez utiliser une action comme celle-ci:

void OuterMethod()
{
    int anything = 1;
    Action InnedMethod = () =>
    {
        int PlitschPlatsch = 2;
    };
    InnedMethod();
}
56
JaredPar

MISE À JOUR: C # 7 a ajouté des fonctions locales ( https://docs.Microsoft.com/en-us/dotnet/articles/csharp/csharp-7#local-functions )

void OuterMethod()
{
    int foo = 1;

    InnerMethod();

    void InnerMethod()
    {
        int bar = 2;
        foo += bar
    }

}

Dans les versions de C # avant C # 7, vous pouvez déclarer un Func ou Action et obtenir quelque chose de similaire:

void OuterMethod()
{
    int foo = 1;
    Action InnerMethod = () => 
    {
        int bar = 2;
        foo += bar;
    } ;

    InnerMethod();
}
41
jeroenh

oui, il existe des moyens. Avec C # 3.0, vous avez le type Func<T> qui fait cela.

Par exemple, j'ai écrit ceci hier:

  var image = Image.FromFile(_file);
  int height = image.Height;
  int width = image.Width;
  double tan = height*1.00/width;
  double angle = (180.0 * Math.Atan(tan) / Math.PI);
  var bitmap = new System.Drawing.Bitmap(image, width, height);
  var g = System.Drawing.Graphics.FromImage(bitmap);
  int fontsize = 26; // starting guess
  Font font = null;
  System.Drawing.SizeF size;

  Func<SizeF,double> angledWidth = new Func<SizeF,double>( (x) =>
      {
          double z = x.Height * Math.Sin(angle) +
          x.Width * Math.Cos(angle);
          return z;
      });

  // enlarge for width
  do
  {
      fontsize+=2;
      if (font != null) font.Dispose();
      font = new Font("Arial", fontsize, System.Drawing.FontStyle.Bold);
      size = g.MeasureString(_text, font);
  }
  while (angledWidth(size)/0.85 < width);

Le but était d'ajouter un filigrane à une image existante. Je voulais que la taille du texte du filigrane soit d'environ 85% de la largeur de l'image. Mais je voulais incliner le texte du filigrane pour qu'il soit écrit sous un angle. Cela a révélé la nécessité de faire des calculs de trig en fonction des angles, et je voulais une petite fonction pour effectuer ce travail. Le Func est parfait pour cela.

Le code ci-dessus définit un Func (une fonction) qui accepte un SizeF et renvoie un double, pour la largeur réelle du texte lorsqu'il est dessiné à l'angle donné. Ce Func est une variable dans une fonction, et la variable elle-même contient une (référence à une) fonction. Je peux alors invoquer cette fonction "privée" dans le cadre où je l'ai définie. Le Func a accès aux autres variables définies avant lui, dans sa portée d'exécution. Ainsi, la variable angle est accessible dans la fonction angledWidth().


Si vous voulez une logique invocable qui renvoie void, vous pouvez utiliser Action<T> , de la même manière. .NET définit les génériques Func qui acceptent N arguments, vous pouvez donc les rendre assez compliqués. Un Func est comme une fonction VB ou une méthode C # qui retourne non vide; une action est comme un VB Sub, ou une méthode C # qui retourne vide) .

16
Cheeso

Cinq ans se sont écoulés depuis que cette question a été posée et maintenant C # 7 arrive.

Il est prévu d'inclure des fonctions locales et est apparemment déjà implémenté.

Fonctions locales (Proposition: # 259) [actuellement dans la future branche]

https://github.com/dotnet/roslyn/issues/259

9
dss539

Le mot clé delegate fait exactement cela.

void OuterMethod()
{
    var InnerMethod = delegate()
    {
        int PlitschPlatsch = 2;
    };

    int anything = 1;
    InnerMethod();
}

N'oubliez pas que, par portée, la variable PlitschPlatsch ne sera pas accessible en dehors d'InnerMethod.

3
zneak

Si vous cherchez principalement à "masquer" une méthode qui n'est qu'un "assistant" ... une autre option est de rendre votre ou vos assistants private. De cette façon, ils ne font pas partie de l'interface publique de votre classe.

Cela présente l'avantage que le ou les assistants peuvent être réutilisés si nécessaire; mais ils ne seront pas "internes" à la méthode d'appel.

1
David

Jetez un œil à méthodes anonymes . Je pense que c'est ce que vous recherchez.

1
T.K.