最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析C#中ref與out參數(shù)傳遞的核心區(qū)別與實(shí)戰(zhàn)指南

 更新時(shí)間:2026年02月26日 09:43:00   作者:bugcome_com  
這篇文章為大家系統(tǒng)梳理了C#中ref與out參數(shù)傳遞的核心區(qū)別與使用場(chǎng)景,ref用于雙向傳遞,調(diào)用前必須初始化,方法內(nèi)可讀寫(xiě),out用于單向輸出,方法內(nèi)必須賦值,調(diào)用前無(wú)需初始化,下面小編就和大家詳細(xì)介紹一下吧

在 C# 中,參數(shù)傳遞方式是一個(gè)基礎(chǔ)卻極易產(chǎn)生誤解的知識(shí)點(diǎn),尤其是 ref 與 out。

很多初學(xué)者會(huì)簡(jiǎn)單地把它們理解為“按引用傳遞”,卻忽略了編譯器約束、數(shù)據(jù)流方向以及與引用類型的真實(shí)關(guān)系,從而在實(shí)際開(kāi)發(fā)中頻繁踩坑

本文將從以下三個(gè)層面系統(tǒng)梳理 ref 與 out

  • 核心語(yǔ)義與編譯器約束
  • 基礎(chǔ)用法與實(shí)戰(zhàn)示例
  • 引用類型(尤其是 string)的特殊行為與本質(zhì)原因

一、ref 與 out 的核心區(qū)別(從“數(shù)據(jù)流”理解)

ref 與 out 的共同點(diǎn)是:

方法可以直接操作“調(diào)用方變量本身”,而不是它的副本。

但二者的設(shè)計(jì)目標(biāo)不同,因此編譯器施加了不同的約束。

核心差異對(duì)照表

對(duì)比維度refout
調(diào)用前是否必須初始化必須初始化不要求初始化
方法內(nèi)是否必須賦值是(強(qiáng)制)
數(shù)據(jù)流方向傳入 + 傳出僅傳出
語(yǔ)義側(cè)重點(diǎn)修改已有值生成新值

本質(zhì)總結(jié)

ref:雙向傳遞

  • -- 調(diào)用方負(fù)責(zé)初始化
  • -- 方法可以讀取、也可以修改

out:?jiǎn)蜗蜉敵?/strong>

  • -- 調(diào)用方不關(guān)心初始值
  • -- 方法必須負(fù)責(zé)賦值
  • 可以將二者理解為:

ref = “我給你一個(gè)值,你可以在它的基礎(chǔ)上改”

out = “你來(lái)負(fù)責(zé)給我一個(gè)結(jié)果”

二、基礎(chǔ)用法實(shí)戰(zhàn)驗(yàn)證

未帶ref 和 out

 internal class Program
 {
     static void Main(string[] args)
     {
         string a = "123";
         List<int> i = new List<int>() { 1, 3, 12, 12, 1 };
         Person person = new Person() { Id = 1 ,Name = "鄧培"};
         aAction(a, i,person);
         Console.WriteLine(a);
         Console.WriteLine(string.Join(" ", i));
         Console.WriteLine(JsonConvert.SerializeObject(person,Formatting.Indented));
         Console.ReadKey();
     }
     static void aAction(string a, List<int> i,Person person)
     {
         a = "123213";
         i = new List<int>() { 1, 21, 312, 312 };
         person.Name = "羅倩";
     }
 }

 public class Person
 {
     public int Id { get; set; }
     public string Name { get; set; }
 }

注意:整體修改值不會(huì)發(fā)生改變

ref:典型的“讀 + 改”場(chǎng)景

class RefDemo
{
    static void Main()
    {
        int num = 10;          // 必須初始化
        Modify(ref num);
        Console.WriteLine(num); // 20
    }

    static void Modify(ref int value)
    {
        value *= 2;           // 既能讀,也能寫(xiě)
    }
}

關(guān)鍵點(diǎn):
  • num 在調(diào)用前必須有值
  • 方法內(nèi)部可以使用該值進(jìn)行計(jì)算
  • 修改結(jié)果會(huì)同步回調(diào)用方

out:典型的“只負(fù)責(zé)輸出結(jié)果”

class OutDemo
{
    static void Main()
    {
        int result;           // 可不初始化
        CreateValue(out result);
        Console.WriteLine(result); // 100
    }

    static void CreateValue(out int value)
    {
        value = 100;          // 必須賦值,否則編譯失敗
    }
}

關(guān)鍵點(diǎn):
  • 調(diào)用方無(wú)需提供初始值
  • 方法必須在返回前完成賦值
  • 編譯器會(huì)強(qiáng)制檢查

三、引用類型的特殊處理:常見(jiàn)誤區(qū)澄清

很多問(wèn)題并不來(lái)自 ref/out,而是來(lái)自對(duì)“引用類型傳參”的誤解。

重要前提:默認(rèn)情況下傳的是什么?

C# 默認(rèn)是“值傳遞”

對(duì)引用類型而言,傳遞的是引用本身的副本

也就是說(shuō):

  • 外部變量保存的是一個(gè)“引用”
  • 方法參數(shù)拿到的是這個(gè)“引用的拷貝”

四、無(wú) ref / out 時(shí)的兩種典型行為

場(chǎng)景一:修改引用指向 ?(不生效)

class Demo
{
    static void Main()
    {
        // 初始化原始變量
        string s = "old value";
        List<int> list = new List<int> { 4, 5, 6 };
        
        // 調(diào)用方法嘗試修改引用指向
        Change(s, list);
        
        // 輸出結(jié)果:原始變量完全沒(méi)變化
        Console.WriteLine(s); // 輸出:old value
        Console.WriteLine(string.Join(",", list)); // 輸出:4,5,6
    }

    static void Change(string s, List<int> list)
    {
        // 修改的是「參數(shù)副本」的引用指向
        s = "new value"; // 讓參數(shù)s的副本指向新字符串
        list = new List<int> { 1, 2, 3 }; // 讓參數(shù)list的副本指向新List
    }
}

調(diào)用后:

  • string 沒(méi)變
  • List 沒(méi)變

原因:

  • 修改的是參數(shù)副本的指向
  • 外部變量的引用未被改變

場(chǎng)景二:修改對(duì)象內(nèi)容 ?(生效)

class Demo
{
    static void Main()
    {
        // 初始化原始Person對(duì)象
        Person p = new Person { Id = 1, Name = "舊名字" };
        
        // 調(diào)用方法修改對(duì)象內(nèi)容
        Change(p);
        
        // 輸出結(jié)果:對(duì)象內(nèi)容被修改
        Console.WriteLine(p.Name); // 輸出:新名字
    }

    static void Change(Person p)
    {
        // 修改的是「對(duì)象內(nèi)部狀態(tài)」,而非引用本身
        p.Name = "新名字";
    }
}

class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

原因:

  • p 與外部變量指向同一對(duì)象
  • 修改的是對(duì)象內(nèi)部狀態(tài),而非引用本身

五、string 為什么“像值類型一樣”?

string 是引用類型,但它是:

不可變(immutable)對(duì)象

using System;

// 示例1:無(wú) ref 時(shí),修改 string 引用指向僅作用于方法內(nèi)副本
class StringImmutableDemo
{
    static void Main()
    {
        // 1. 初始化原始字符串變量
        string originalStr = "123";
        Console.WriteLine($"【調(diào)用方法前】原始變量 originalStr = {originalStr}");
        // 輸出:【調(diào)用方法前】原始變量 originalStr = 123

        // 2. 調(diào)用方法嘗試修改字符串
        TryChangeString(originalStr);

        // 3. 調(diào)用方法后,原始變量無(wú)變化
        Console.WriteLine($"【調(diào)用方法后】原始變量 originalStr = {originalStr}");
        // 輸出:【調(diào)用方法后】原始變量 originalStr = 123
    }

    /// <summary>
    /// 無(wú) ref:修改的是方法內(nèi)參數(shù)副本的引用指向
    /// </summary>
    static void TryChangeString(string strParam)
    {
        // 注意:不是修改原有"123"的內(nèi)容,而是創(chuàng)建新字符串"456"
        strParam = "456";
        Console.WriteLine($"【方法內(nèi)部】參數(shù)副本 strParam = {strParam}");
        // 輸出:【方法內(nèi)部】參數(shù)副本 strParam = 456
    }
}

運(yùn)行輸出

  • 【調(diào)用方法前】原始變量 originalStr = 123
  • 【方法內(nèi)部】參數(shù)副本 strParam = 456
  • 【調(diào)用方法后】原始變量 originalStr = 123

這不是“修改字符串”,而是:

  • 創(chuàng)建新字符串 "456"
  • 讓變量 s 指向新對(duì)象

因此:

  • 不加 ref → 只修改局部副本
  • 加 ref → 才能修改外部引用指向

六、加 ref 后:修改引用指向生效

using System;
using System.Collections.Generic;

// 示例2:加 ref 后,修改 string/List 的引用指向生效
class RefChangeReferenceDemo
{
    static void Main()
    {
        // 1. 初始化原始變量
        string originalStr = "123";
        List<int> originalList = new List<int> { 9, 9 };

        Console.WriteLine("【調(diào)用方法前】");
        Console.WriteLine($"原始字符串 originalStr = {originalStr}");
        Console.WriteLine($"原始列表 originalList = [{string.Join(",", originalList)}]");
        // 輸出:
        // 原始字符串 originalStr = 123
        // 原始列表 originalList = [9,9]

        // 2. 加 ref 調(diào)用方法,修改引用指向
        ChangeReference(ref originalStr, ref originalList);

        Console.WriteLine("\n【調(diào)用方法后】");
        Console.WriteLine($"原始字符串 originalStr = {originalStr}");
        Console.WriteLine($"原始列表 originalList = [{string.Join(",", originalList)}]");
        // 輸出:
        // 原始字符串 originalStr = 456
        // 原始列表 originalList = [1,2,3]
    }

    /// <summary>
    /// 加 ref:直接操作原始變量的引用指向
    /// </summary>
    static void ChangeReference(ref string strParam, ref List<int> listParam)
    {
        // 直接修改原始字符串變量的指向(新建"456"并讓原始變量指向它)
        strParam = "456";
        // 直接修改原始列表變量的指向(新建List并讓原始變量指向它)
        listParam = new List<int> { 1, 2, 3 };
    }
}

運(yùn)行輸出

【調(diào)用方法前】
原始字符串 originalStr = 123
原始列表 originalList = [9,9]

【調(diào)用方法后】
原始字符串 originalStr = 456
原始列表 originalList = [1,2,3]

結(jié)果:

  • s 指向新字符串
  • list 指向新集合

本質(zhì):

ref 傳遞的不是“引用的副本”,而是引用變量本身

七、ref 與 out 的典型適用場(chǎng)景

適合使用 ref 的情況

  • 需要在原有值基礎(chǔ)上修改
  • 需要替換引用類型的整體對(duì)象
  • 典型場(chǎng)景:交換變量、緩存對(duì)象復(fù)用

適合使用 out 的情況

  • 方法職責(zé)是“生成結(jié)果”
  • 不關(guān)心調(diào)用前的初始值
  • 返回多個(gè)值但不想定義新類型
bool success = int.TryParse("123", out int value);

八、實(shí)踐注意事項(xiàng)(非常重要)

ref / out 必須 調(diào)用方 + 方法簽名同時(shí)聲明

out 在 C# 7+ 支持內(nèi)聯(lián)聲明

避免濫用

  • --會(huì)降低可讀性
  • --會(huì)增加理解成本
  • --優(yōu)先考慮返回值或 DTO

總結(jié)(核心記憶點(diǎn))

  • ref雙向傳遞,調(diào)用前必須初始化
  • out單向輸出,方法內(nèi)必須賦值
  • 默認(rèn)傳遞的是引用的副本
  • 修改對(duì)象內(nèi)容 ≠ 修改引用指向
  • string 因不可變,行為更接近值類型
  • 修改引用指向 → 必須使用 ref / out

如果你能在腦中始終區(qū)分清楚這三點(diǎn):

值 / 引用 / 引用的副本

那么 ref 與 out 將不再是坑,而是工具。

到此這篇關(guān)于淺析C#中ref與out參數(shù)傳遞的核心區(qū)別與實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)C# ref與out參數(shù)傳遞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Unity的IPreprocessBuild實(shí)用案例深入解析

    Unity的IPreprocessBuild實(shí)用案例深入解析

    這篇文章主要為大家介紹了Unity的IPreprocessBuild實(shí)用案例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • C#訪問(wèn)命令行的兩種方法

    C#訪問(wèn)命令行的兩種方法

    這篇文章主要介紹了C#訪問(wèn)命令行的兩種方法,實(shí)例分析了C#操作命令行的兩種常用技巧,需要的朋友可以參考下
    2015-06-06
  • 深入解析C#中的async和await關(guān)鍵字

    深入解析C#中的async和await關(guān)鍵字

    C#語(yǔ)言中的async和await關(guān)鍵字使得編寫(xiě)異步代碼變得更加簡(jiǎn)潔和易讀,本文將深入解析C#中的async和await,幫助您更好地理解它們的工作原理和用法,,需要的朋友可以參考下
    2024-05-05
  • C#畢業(yè)設(shè)計(jì)之Winform零壓健身房管理系統(tǒng)

    C#畢業(yè)設(shè)計(jì)之Winform零壓健身房管理系統(tǒng)

    本文介紹了個(gè)人的《零壓健身房管理系統(tǒng)(扁平化)》的基本流程和功能點(diǎn)的介紹,虛心接受各位的意見(jiàn),歡迎在提出寶貴的意見(jiàn),大家一起探討學(xué)習(xí)
    2021-09-09
  • c#使用process.start啟動(dòng)程序報(bào)錯(cuò)解決方法

    c#使用process.start啟動(dòng)程序報(bào)錯(cuò)解決方法

    c#使用process.start啟動(dòng)程序報(bào)錯(cuò)解決方法,大家參考使用吧
    2013-12-12
  • C#代碼性能測(cè)試類(簡(jiǎn)單實(shí)用)

    C#代碼性能測(cè)試類(簡(jiǎn)單實(shí)用)

    這篇文章主要介紹了C#代碼性能測(cè)試類(簡(jiǎn)單實(shí)用),本文直接給出實(shí)現(xiàn)代碼和使用示例,需要的朋友可以參考下
    2015-06-06
  • 使用C#代碼壓平PDF表單字段的實(shí)現(xiàn)方法

    使用C#代碼壓平PDF表單字段的實(shí)現(xiàn)方法

    壓平表單字段是防止他人修改或刪除 PDF 表單內(nèi)容的一種有效方式,壓平后,表單字段將失去編輯和填寫(xiě)功能,其內(nèi)容會(huì)以普通文本的形式顯示在文檔中,本文將介紹如何在 C# 和 VB.NET 中實(shí)現(xiàn) PDF 表單字段壓平,需要的朋友可以參考下
    2026-05-05
  • C#?winform跨線程操作控件的實(shí)現(xiàn)

    C#?winform跨線程操作控件的實(shí)現(xiàn)

    本文主要介紹了C#?winform跨線程操作控件的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Unity實(shí)現(xiàn)截圖功能

    Unity實(shí)現(xiàn)截圖功能

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)截圖功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • C#進(jìn)度軸控件分享

    C#進(jìn)度軸控件分享

    這里給大家介紹的是使用C#實(shí)現(xiàn)的進(jìn)度軸的方法和示例,非常的實(shí)用,有需要的小伙伴可以參考下。
    2015-06-06

最新評(píng)論

琼中| 应用必备| 许昌县| 岳西县| 巴中市| 阳谷县| 南投市| 山丹县| 江源县| 莒南县| 荥阳市| 如东县| 桦甸市| 若尔盖县| 建始县| 木里| 金堂县| 察雅县| 侯马市| 泰顺县| 汾阳市| 四川省| 姜堰市| 札达县| 道孚县| 磐石市| 罗田县| 新平| 资兴市| 马公市| 普陀区| 陈巴尔虎旗| 天水市| 五华县| 岳阳县| 邵阳县| 甘谷县| 策勒县| 英超| 浏阳市| 亳州市|