亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#中閉包的實現(xiàn)和注意事項詳解

 更新時間:2025年01月02日 10:27:12   作者:嘯貓先生  
閉包并不是某一個語言中特有的概念,在主流的編程語言中都有這個特性,閉包可以讓一個內(nèi)部方法可以訪問它所在外部方法中的變量,并可以對變量的值進行修改,即使在外部方法的生命周期已經(jīng)結束后,本文給大家介紹了C#中閉包的實現(xiàn)和注意事項,需要的朋友可以參考下

閉包的定義

閉包并不是某一個語言中特有的概念,在主流的編程語言中都有這個特性。閉包可以讓一個內(nèi)部方法可以訪問它所在外部方法中的變量,并可以對變量的值進行修改,即使在外部方法的生命周期已經(jīng)結束后。

不知道在看完上面這一串定義之后,可以明白閉包是個什么東西嗎,反正我在一開始看完是不知道這是在說什么,不過沒關系,我們可以先往下具體看閉包的一個例子。

C#中閉包的實現(xiàn)

下面是一個最簡單的閉包,這里使用了委托和Lambda表達式,不過使用局部函數(shù)也是一樣的效果,這兩者之間的區(qū)別我們之后去討論,這里就以使用委托的版本來看一下后臺干了什么。

class Program
{
    // 使用委托和 Lambda 表達式
    static void Main(string[] args)
    {
        int num = 0;

        Action test = () =>
        {
            num++;
            Console.WriteLine(num);
        };
        test();
    }
}
class Program
{
    // 使用局部函數(shù)
    static void Main(string[] args)
    {
        int num = 0;
        Test();
        return;
        
        void Test()
        {
            num++;
            Console.WriteLine(num);
        }
    }
}

我們看構建后的低級別C#可以看出來,在Main方法中new了一個類,這個類中有一個num的成員變量,我們形成閉包的方法實際操作的是這個成員變量,這就解釋了為什么外部方法的生命周期結束后,仍然可以訪問到在其定義的變量。

閉包的注意事項

Lambda表達式和局部方法

我們先看下面這個場景,在這個場景我們使用了一個類中的某個方法并想要在完成后執(zhí)行一個回調(diào)。

這里使用Lambda表達式和使用局部函數(shù)有兩種情況,一是會捕獲封閉范圍內(nèi)的變量時,如下面這段代碼,這時使用局部函數(shù)和使用Lambda表達式一樣,都會形成一個閉包,并使用類的成員變量來實現(xiàn),如我在解釋C#中閉包的實現(xiàn)時舉得那個例子。

class Program
{
    static void Main(string[] args)
    {
        int num = 0;
        TestClass test = new TestClass();
        for (int i = 0; i < 3; i++)
        {
            test.DoSomething(() =>
            {
                num++;
                Console.WriteLine($"DoSomething finish {num}");
            });
        }
    }
}


class TestClass
{
    public void DoSomething(Action callback)
    {
        Console.WriteLine("DoSomething");
        
        // 執(zhí)行回調(diào)
callback.Invoke();
    }
}

但是如果沒有捕獲任何變量時,如下面這種情況,可以看到使用局部函數(shù)的方式?jīng)]有形成閉包,局部函數(shù)最終變成了一個靜態(tài)函數(shù)。而使用委托和 Lambda 表達式的盡管沒有捕獲任何變量,但還是創(chuàng)建了一個類,雖然這個類只會實例化一次。

class Program
{
    // 使用局部函數(shù),且沒有捕獲封閉范圍內(nèi)的變量
    static void Main(string[] args)
    {
        TestClass test = new TestClass();
        for (int i = 0; i < 3; i++)
        {
            test.DoSomething(DoSomethingCallBack);
        }
        return;
        
        void DoSomethingCallBack()
        {
            Console.WriteLine($"DoSomething finish");
        }
    }
}
class Program
{
    // 使用委托和 Lambda 表達式,且沒有捕獲封閉范圍內(nèi)的變量
    static void Main(string[] args)
    {
        TestClass test = new TestClass();
        for (int i = 0; i < 3; i++)
        {
            test.DoSomething(() =>
            {
                Console.WriteLine("DoSomething finish");
            });
        }
    }
}

配合for循環(huán)返回多個函數(shù)

閉包和for循環(huán)這也是一個經(jīng)典的錯誤了,讓我們來看下面這段代碼,這里乍一看沒什么問題,我們預期輸出的結果是0,1。

class Program
{
    static void Main(string[] args)
    {
        int count = 2;
        Action[] fun = CreateActions(count);
        for (int i = 0; i < count; i++)
        {
            fun[i].Invoke();
        }
        return;

        Action[] CreateActions(int count)
        {
            Action[] actions = new Action[count];
            for (int i = 0; i < count; i++)
            {
                actions[i] = () => Console.WriteLine(i);
            }
            return actions;
        }
    }
}

但是我們實際運行一下,可以發(fā)現(xiàn)輸出的結果是2,2。

這里我們看編譯之后的代碼,可以看出我們本質(zhì)操控的其實是同一個<>c__DisplayClass0_0對象的成員變量i,所以自然輸出都都是i自增之后的值。

這里改起來也比較容易,只需將for循環(huán)改成下面這樣就行了。

for (int i = 0; i < count; i++)
{
    int j = i;
    actions[i] = () => Console.WriteLine(j);
}

這里要注意,int j = i;一定要在for循環(huán)里面,這樣閉包才會創(chuàng)建3個不同的對象。如果像下面這樣寫,本質(zhì)和最開始沒有太大區(qū)別,還是操縱著一個對象。

int j;
for (int i = 0; i < count; i++)
{
    j = i;
    actions[i] = () => Console.WriteLine(j);
}

以上就是C#中閉包的實現(xiàn)和注意事項詳解的詳細內(nèi)容,更多關于C#閉包實現(xiàn)和注意事項的資料請關注腳本之家其它相關文章!

相關文章

最新評論