c# - अनुप्रयोगों को डिज़ाइन करते समय आप Func<> और action<> का उपयोग कैसे करते हैं?




delegates anonymous-methods (6)

Func <> और action <> के बारे में मुझे जो भी उदाहरण मिल सकते हैं, वे नीचे दिए गए एक जैसा हैं जहां आप देखते हैं कि वे तकनीकी रूप से कैसे काम करते हैं लेकिन मैं उन उदाहरणों में उपयोग करना चाहता हूं जहां वे उन समस्याओं को हल करते हैं जिन्हें पहले हल नहीं किया जा सका या कर सकता था केवल एक और जटिल तरीके से हल किया जाए, यानी मुझे पता है कि वे कैसे काम करते हैं और मैं देख सकता हूं कि वे तंग और शक्तिशाली हैं , इसलिए मैं उन्हें समझना चाहता हूं कि वे किस प्रकार की समस्याएं हल करते हैं और मैं उन्हें कैसे उपयोग कर सकता हूं अनुप्रयोगों का डिजाइन।

असली समस्याओं को हल करने के लिए आप किस तरह से (पैटर्न) Func <> और action <> का उपयोग करते हैं?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestFunc8282
{
    class Program
    {
        static void Main(string[] args)
        {
            //func with delegate
            Func<string, string> convert = delegate(string s)
            {
                return s.ToUpper();
            };

            //func with lambda
            Func<string, string> convert2 = s => s.Substring(3, 10);

            //action
            Action<int,string> recordIt = (i,title) =>
                {
                    Console.WriteLine("--- {0}:",title);
                    Console.WriteLine("Adding five to {0}:", i);
                    Console.WriteLine(i + 5);
                };

            Console.WriteLine(convert("This is the first test."));
            Console.WriteLine(convert2("This is the second test."));
            recordIt(5, "First one");
            recordIt(3, "Second one");

            Console.ReadLine();

        }
    }
}

Linq का उपयोग करना।

List<int> list = { 1, 2, 3, 4 };

var even = list.Where(i => i % 2);

एक Func<int, bool> Where है के लिए पैरामीटर।

लैम्ब्डा अभिव्यक्तियां सी # के मेरे पसंदीदा भागों में से एक हैं। :)


असल में, मैंने इसे स्टैक ओवरफ्लो पर पाया (कम से कम - विचार):

public static T Get<T>  
    (string cacheKey, HttpContextBase context, Func<T> getItemCallback)
            where T : class
{
    T item = Get<T>(cacheKey, context);
    if (item == null) {
        item = getItemCallback();
        context.Cache.Insert(cacheKey, item);
    }

    return item;
}

एक चीज जिसका मैं इसका उपयोग करता हूं वह महंगी विधि कॉल का कैशिंग है जो कभी भी इनपुट को नहीं बदला जाता है:

public static Func<TArgument, TResult> Memoize<TArgument, TResult>(this Func<TArgument, TResult> f)
{
    Dictionary<TArgument, TResult> values;

    var methodDictionaries = new Dictionary<string, Dictionary<TArgument, TResult>>();

    var name = f.Method.Name;
    if (!methodDictionaries.TryGetValue(name, out values))
    {
        values = new Dictionary<TArgument, TResult>();

        methodDictionaries.Add(name, values);
    }

    return a =>
    {
        TResult value;

        if (!values.TryGetValue(a, out value))
        {
            value = f(a);
            values.Add(a, value);
        }

        return value;
    };
}

डिफ़ॉल्ट रिकर्सिव फाइबोनैकी उदाहरण:

class Foo
{
  public Func<int,int> Fibonacci = (n) =>
  {
    return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
  };

  public Foo()
  {
    Fibonacci = Fibonacci.Memoize();

    for (int i=0; i<50; i++)
      Console.WriteLine(Fibonacci(i));
  }
}

डुनो अगर यह दो बार एक ही प्रश्न का उत्तर देने के लिए खराब फॉर्म है, लेकिन सामान्य रूप से इन प्रकारों के बेहतर उपयोग के लिए कुछ विचार प्राप्त करने के लिए मैं फंक्शनल प्रोग्रामिंग पर जेरेमी मिलर के एमएसडीएन लेख को पढ़ने का सुझाव देता हूं:

हर रोज .NET विकास के लिए कार्यात्मक प्रोग्रामिंग


मैं एक लेनदेन में निष्पादन डेटाबेस संचालन को अच्छी तरह से समाहित करने के लिए एक क्रिया का उपयोग करता हूं:

public class InTran
{
    protected virtual string ConnString
    {
        get { return ConfigurationManager.AppSettings["YourDBConnString"]; }
    }

    public void Exec(Action<DBTransaction> a)
    {
        using (var dbTran = new DBTransaction(ConnString))
        {
            try
            {
                a(dbTran);
                dbTran.Commit();
            }
            catch
            {
                dbTran.Rollback();
                throw;
            }
        }
    }
}

अब लेनदेन में निष्पादित करने के लिए मैं बस करता हूं

new InTran().Exec(tran => ...some SQL operation...);

इनट्रान क्लास एक सामान्य लाइब्रेरी में रह सकती है, डुप्लिकेशंस को कम कर सकती है और भविष्य में कार्यक्षमता समायोजन के लिए एक गायक स्थान प्रदान करती है।


मैं हर समय Action और Func प्रतिनिधियों का उपयोग करता हूं। मैं आम तौर पर उन्हें अंतरिक्ष बचाने के लिए लैम्ब्डा सिंटैक्स के साथ घोषित करता हूं और मुख्य रूप से बड़े तरीकों के आकार को कम करने के लिए उनका उपयोग करता हूं। जैसे-जैसे मैं अपनी विधि की समीक्षा करता हूं, कभी-कभी कोड सेगमेंट समान होते हैं। उन मामलों में, मैं Action या Func में समान कोड सेगमेंट लपेटता हूं। प्रतिनिधि का उपयोग अनावश्यक कोड को कम करता है, कोड सेगमेंट में एक अच्छा हस्ताक्षर दें और आवश्यकता होने पर आसानी से किसी विधि को प्रचारित किया जा सकता है।

मैं डेल्फी कोड लिखता था और आप एक समारोह के भीतर एक समारोह घोषित कर सकते थे। एक्शन और फंक सी # में मेरे लिए इसी व्यवहार को पूरा करते हैं।

एक प्रतिनिधि के साथ नियंत्रण पुनर्निर्माण का नमूना यहां दिया गया है:

private void Form1_Load(object sender, EventArgs e)
{
    //adjust control positions without delegate
    int left = 24;

    label1.Left = left;
    left += label1.Width + 24;

    button1.Left = left;
    left += button1.Width + 24;

    checkBox1.Left = left;
    left += checkBox1.Width + 24;

    //adjust control positions with delegate. better
    left = 24;
    Action<Control> moveLeft = c => 
    {
        c.Left = left;
        left += c.Width + 24; 
    };
    moveLeft(label1);
    moveLeft(button1);
    moveLeft(checkBox1);
}




func