Question

Je ne peux pas sembler pour envelopper ma tête autour d'eux.

Si je comprends qu'il est logique d'ajouter dynamiquement à une classe. Les cours sont-dans le cadre préparé pour cela?

Pourquoi devrais-je prolonger simplement la classe et ajouter la fonctionnalité à elle dans l'extension. Je serais globalement accessible et autant que je sache beaucoup plus facile à entretenir.

Je l'ai lu il y a 4 types de foncteurs:


Comparer fermeture
prédicats
Transformateur

Nous devrions probablement manipuler chacun d'eux.

p.s. est là quelque chose comme ça dans vb?

Je peux donc dire que je pense des expressions lambda sont foncteurs. Cela efface les choses pour moi un peu :) (hehe)

  • Les expressions lambda sont foncteurs?
  • Les fonctions anonymes sont foncteurs?

Mais j'ai posé cette question parce que je suis tombé sur un autre type de fucntors à savoir celles-ci:

delegate void FunctorDelegate(int value);
class Addition {
    FunctorDelegate _delegate;

    public Addition AddDelegate(FunctorDelegate deleg) {
        _delegate += deleg;
        return this;
    }
    public int AddAllElements(IList< int> list) {
        int runningTotal = 0;
        foreach( int value in list) {
            runningTotal += value;
            _delegate(value);
        }
        return runningTotal;
    }
}

Et puis l'appeler avec ceci:

 int runningTotal = new Addition()
     .AddDelegate(new FunctorDelegate(
                     delegate(int value) {
                         if ((value % 2) == 1) {
                             runningOddTotal += value;
                         }
                     }))
    .AddDelegate(new FunctorDelegate(
                     delegate(int value) {
                         if ((value % 2) == 0) {
                             runningEvenTotal += value;
                         }
                     }))
    .AddAllElements(list);

Donc pas de choses de style de fantaisie lambda.

Maintenant, j'ai cet exemple, mais ce n'est pas du tout pourquoi cela est une « bonne » solution.

sont délégués (foncteurs) utilisés comme des expressions lambda ou des méthodes anonymes « dans la plupart des cas » juste là comme un raccourci pour le programmeur? Il y a aussi loin que je ne vois que quelques cas où ils sont en fait le choix preferred pour un problème.

Était-ce utile?

La solution

Je pense que vous confondez termes de langues différentes. Vous semblez utiliser « Functor » dans le C ++ ou Java sens, par exemple voir la page wikipedia . En C ++, il est un objet d'une classe qui surchargent l'opérateur d'appel de fonction, il peut donc être utilisé en fonction, mais avec l'état.

Ceci est logiquement la même chose que d'un délégué lié à une méthode d'instance en C # (ou tout autre langage .NET).

Il existe trois façons d'écrire une telle chose. Tout d'abord, vous pouvez écrire une méthode ordinaire, puis attribuez-lui le nom de la méthode à une variable de délégué.

void MyMethod() { Console.WriteLine("Hi!"); }

void Foo()
{
    Action a = MyMethod;
    a();
}

Deuxièmement, vous pouvez utiliser la syntaxe de méthode anonyme, Introduite en C # 2.0:

void Foo()
{
    Action a = delegate { Console.WriteLine("Hi!"); }
    a();
}

Troisièmement, vous pouvez utiliser la syntaxe lambda, Introduite en C # 3.0:

void Foo()
{
    Action a = () => Console.WriteLine("Hi!");
    a();
}

L'avantage de ces deux derniers est que le corps de la méthode peut lire et écrire des variables locales de la méthode contenant.

L'avantage de la syntaxe lambda par rapport aux méthodes anon-sont qu'il est plus succinct et il ne l'inférence de type sur les paramètres.

Mise à jour: L'avantage de anon-méthodes (mot-clé) sur delegate lambdas est que vous pouvez omettre les paramètres tout à fait si vous ne les avez pas besoin:

// correct way using lambda
button.Click += (sender, eventArgs) => MessageBox.Show("Clicked!");

// compile error - wrong number of arguments
button.Click += () => MessageBox.Show("Clicked!");

// anon method, omitting arguments, works fine
button.Click += delegate { MessageBox.Show("Clicked!"); };

Je ne connais qu'une seule situation où cela vaut la peine de savoir, ce qui est un événement lors de l'initialisation de sorte que vous ne devez pas vérifier null avant sa cuisson:

event EventHandler Birthday = delegate { };

Evite beaucoup de bêtises ailleurs.

Enfin, vous mentionnez qu'il ya quatre types de foncteur. En fait, il y a une infinité de déléguer éventuellement types, bien que certains auteurs peuvent avoir leurs favoris et il y aura évidemment des modèles communs. Un Action ou Command ne prend aucun paramètre et renvoie void, et un prédicat prend une instance d'un certain type et retourne true ou false.

En C # 3.0, vous pouvez concocter un délégué jusqu'à quatre paramètres de tous les types que vous aimez:

Func<string, int, double> f;  // takes a string and an in, returns a double

Re: Mise à jour Question

Vous demandez (je pense) s'il y a beaucoup de cas d'utilisation pour lambdas. Il y a plus que ce qui peut éventuellement être énumérés!

Vous les voyez plus souvent au milieu des expressions plus grandes qui opèrent sur des séquences (listes calculées sur la volée). Supposons que j'ai une liste de personnes, et je veux une liste de personnes exactement quarante ans:

var exactlyForty = people.Where(person => person.Age == 40);

La méthode Where est une méthode d'extension sur l'interface IEnumerable<T>, où T dans ce cas est une sorte de classe Person.

Ceci est connu dans le .NET comme « LINQ to Objects », mais connu ailleurs aussi pure programmation fonctionnelle sur des séquences ou des flux ou des listes « paresseux » (tous les noms différents pour la même chose).

Autres conseils

En termes .NET, I pense ce que vous décrivez est le Delegate -. Et il existe dans tous .NET, non seulement C #

Je ne suis pas sûr qu'une « fermeture » serait un « type » dans le même était un comparateur / prédicats / transformateur, car en termes de C # une fermeture est tout simplement un détail de mise en œuvre, mais peut être l'un de ces trois.

Dans .NET, les délégués sont utilisés de deux manières:

  • comme mécanisme de concours complet
  • pour offrir une programmation de style fonctionnel

Le premier est important, mais il semble que vous êtes plus intéressés par la seconde. En réalité, ils fonctionnent comme des interfaces unique méthode ... considérer:

List<int> vals = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> evenVals = vals.FindAll(i => i % 2 == 0); // predicate
List<string> valsAsStrings = vals.ConvertAll(i => i.ToString()); // transformer
// sort descending
vals.Sort((x, y) => y.CompareTo(x)); // comparer

Une fermeture est plus où nous apportons des possibilités supplémentaires de extérieur le délégué dans le délégué:

int max = int.Parse(Console.ReadLine()); // perhaps 6
List<int> limited = vals.FindAll(i => i <= max);

ici la max est capturé dans le délégué en fermeture.

Re "sont des classes dans le cadre prepaired pour cela?" - beaucoup sont, et LINQ va long manière de permettre ce encore plus large. LINQ fournit des méthodes d'extension sur (par exemple) tous IEnumerable<T> - ce qui signifie que les collections sans accès par délégué-les Aquire gratuitement:

int[] data = { 1,2,3,4,5,6,7,8,9 };
var oddData = data.Where( i => i % 2 == 1 );
var descending = data.OrderBy(i => -i);
var asStrings = data.Select(i => i.ToString());

Voici les méthodes de Where et OrderBy sont des méthodes d'extension LINQ qui prennent les délégués.

Intéressant avec la terminologie; mon interprétation spontanée du terme « Functor » était qu'il se référait à des méthodes anonymes. Ce sera donc mon avis sur la question.

Voici quelques-unes de mes utilisations typiques:

Les comparaisons (en général pour le tri d'une liste):

List<int> ints = new List<int>();
ints.AddRange(new int[] { 9, 5, 7, 4, 3, 5, 3 });
ints.Sort(new Comparison<int>(delegate(int x, int y)
    {
        return x.CompareTo(y);
    }));
// yes I am aware the ints.Sort() would yield the same result, but hey, it's just
// a conceptual code sample ;o)

// and the shorter .NET 3.5 version:
ints.Sort((x, y) =>
{
    return x.CompareTo(y);
});

Je vais utiliser cette approche pour les comparaisons, plutôt que d'avoir dans sa propre méthode d'utilisation d'un délégué pour cette méthode, dans les cas où ce genre particulier se produit dans un seul endroit. S'il est probable que je veux utiliser la même comparaison ailleurs, il arrive à vivre dans sa propre méthode réutilisable.

Une autre de mes utilisations assez courantes est dans les tests unitaires, lorsque le test repose sur un événement soulevée. J'ai trouvé que, pour être indispensable lorsque les flux de travail des tests unitaires dans Workflow Foundation:

WorkflowRuntime runtime = WorkflowHost.Runtime;  
WorkflowInstance instance = runtime.CreateWorkflow(typeof(CreateFile)); 
EventHandler<WorkflowEventArgs> WorkflowIdledHandler = delegate(object sender, WorkflowEventArgs e)
{
    // get the ICreateFileService instance from the runtime  
    ISomeWorkflowService service = WorkflowHost.Runtime.GetService<ISomeWorkflowService>();

    // set the desired file content  
    service.DoSomeWork(instance.InstanceId, inputData);
};  
// attach event handler
runtime.WorkflowIdled += WorkflowIdledHandler;  

instance.Start();  
// perform the test, and then detach the event handler
runtime.WorkflowIdled -= WorkflowIdledHandler; 

Dans ce cas, il est plus simple d'avoir le gestionnaire d'événements déclarés comme méthodes anonymes car il utilise la variable instance qui est définie dans le cadre de la méthode de test unitaire. Si j'avais intstead choisi de implelment le gestionnaire d'événements comme sa propre méthode distincte, je aurais besoin aussi de trouver un moyen pour elle de ramasser instance, probablement par l'introduction d'un membre de niveau de classe, ce qui ne semble pas comme un design parfait dans un test unitaire classe.

Il y a plus de cas où je trouve dans mon code, mais ils ont généralement une ou deux choses en commun:

  • Je n'ai aucun intérêt à référencer ce morceau de code à partir de nulle part ailleurs que dans cet endroit particulier .
  • La méthode doit avoir accès à des données qui seraient hors du champ d'application d'une méthode régulière

La vraie réponse est qu'un foncteur est un type d'objet mathématique, et est « réifiée » par les différentes langues de différentes façons. Par exemple, supposons que vous avez un objet « conteneur » qui stocke un tas d'autres objets du même type. (Par exemple, un ensemble ou un tableau) Ensuite, si votre langue avait une méthode qui vous permettra de « carte » sur le conteneur, de sorte que l'on pourrait appeler une méthode sur chaque objet dans le conteneur, le conteneur serait foncteur .

En d'autres termes, un foncteur est un récipient avec une méthode qui permet de transmettre une méthode pour ses choses contenues.

Chaque langue a sa propre façon de le faire, et ils amalgamer parfois l'utilisation. Par exemple, C ++ utilise des pointeurs de fonction pour représenter le « passage dans » d'une méthode, et appelle le pointeur de la fonction d'un « foncteur. » Les délégués sont juste une poignée sur les méthodes que vous pouvez passer. Vous utilisez la terminologie « mal », comme C ++ fait.

Haskell obtient droit. Vous déclarez qu'un type implémente l'interface foncteur, et vous obtenez la méthode de mise en correspondance.

Fonctions (comme lambdas) sont foncteurs aussi, mais il peut être difficile de penser genre de d'une fonction comme un « conteneur ». En bref, une fonction est un « conteneur » autour d'une valeur de retour, conçu de telle sorte que la valeur de retour (éventuellement) dépend des arguments de la fonction.

Je suis sûr que vous voulez dire des expressions lambda. Ce sont de petites fonctions, vous pouvez écrire très rapidement, et ils ont la caractéristique « => » opérateur. Ce sont une nouvelle fonctionnalité de C # 3.0.

Cet exemple sera un transformateur classique; d'utiliser l'un nous avons besoin d'un délégué pour définir la signature de la fonction Lambda.

delegate int Transformer(int i);

Déclarer un Lambda avec ce délégué:

Transformer sqr = x => x * x;

On peut l'utiliser comme une fonction normale:

Console.WriteLine(sqr(3)); //9

Ils sont utilisés dans requêtes LINQ beaucoup, par exemple à Trier (Comparer), à la recherche par le biais (prédicats).

Le livre "C # Pocket Reference" (en dehors de beign le meilleur autour, à mon avis, a une très bonne partie sur lambdas. (ISBN 978-0-596-51922-3)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top