C#基础知识-方法参数Params、In、Ref、Out

方法参数时可以使用的关键字:

  • params 指定此参数采用可变数量的参数。
  • in 指定此参数由引用传递,但只由调用方法读取。
  • ref 指定此参数由引用传递,可能由调用方法读取或写入。
  • out 指定此参数由引用传递,由调用方法写入。

Params:

使用 params 关键字可以指定采用数目可变的参数的方法参数。 参数类型必须是一维数组。
在方法声明中的 params 关键字之后不允许有任何其他参数,并且在方法声明中只允许有一个 params 关键字。
使用 params 参数调用方法时,可以传入:

  • 数组元素类型的参数的逗号分隔列表。
  • 指定类型的参数的数组。
  • 无参数。 如果未发送任何参数,则 params 列表的长度为零。
public class MyClass
{
    public static void UseParams(params int[] list)
    {
        for (int i = 0; i < list.Length; i++)
        {
            Console.Write(list[i] + " ");
        }
        Console.WriteLine();
    }

    public static void UseParams2(params object[] list)
    {
        for (int i = 0; i < list.Length; i++)
        {
            Console.Write(list[i] + " ");
        }
        Console.WriteLine();
    }

    static void Main()
    {
        // You can send a comma-separated list of arguments of the
        // specified type.
        UseParams(1, 2, 3, 4);
        UseParams2(1, 'a', "test");

        // A params parameter accepts zero or more arguments.
        // The following calling statement displays only a blank line.
        UseParams2();

        // An array argument can be passed, as long as the array
        // type matches the parameter type of the method being called.
        int[] myIntArray = { 5, 6, 7, 8, 9 };
        UseParams(myIntArray);

        object[] myObjArray = { 2, 'b', "test", "again" };
        UseParams2(myObjArray);

        // The following call causes a compiler error because the object
        // array cannot be converted into an integer array.
        //UseParams(myObjArray);

        // The following call does not cause an error, but the entire
        // integer array becomes the first element of the params array.
        UseParams2(myIntArray);
    }
}

In:

in 关键字会导致按引用传递参数,但确保未修改参数。
它让形参成为实参的别名,这必须是变量。
in 参数无法通过调用的方法进行修改。
in 形参的实参必须先经过初始化,然后才能传递。
在这里插入图片描述
in、ref 和 out 关键字不被视为用于重载决议的方法签名的一部分。什么意思呢?看下图
在这里插入图片描述
如果使用In关键字,就不能使用Ref和Out;
如果使用Ref关键字,就不能使用In和Out;
如果使用Out关键字,就不能使用In和Ref;
重载决策规则

  1. 定义使用 in 参数的方法是一项潜在的性能优化。 某些struct类型参数可能很大,在紧凑的循环或关键代码路径中调用方法时,复制这些结构的成本就很高。 方法声明in参数以指定参数可能按引用安全传递,因为所调用的方法不修改该参数的状态。 按引用传递这些参数可以避(可能产生的)高昂的复制成本。
  2. 指定 in 会声明你想按引用传递参数。在调用站点省略 in 就会通知编译器你将允许它创建临时变量,并按只读引用传递至方法。 编译器创建临时变量以克服一些 in 参数的限制:
    - 临时变量允许将编译时常数作为 in 参数。
    - 临时变量允许使用属性或 in 参数的其他表达式。
    - 存在从实参类型到形参类型的隐式转换时,临时变量允许使用实参。
    在这里插入图片描述

在这里插入图片描述

Ref:

ref 关键字指示按引用传递值。 它用在四种不同的上下文中:

  • 在方法签名和方法调用中,按引用将参数传递给方法。
  • 在方法签名中,按引用将值返回给调用方。
  • 在成员正文中,指示引用返回值是否作为调用方欲修改的引用被存储在本地。 或指示局部变量按引用访问另一个值。
  • 在 struct 声明中,声明 ref struct 或 readonly ref struct。

使用 ref 关键字时,它指示参数按引用传递,而非按值传递。 ref 关键字让形参成为实参的别名,这必须是变量。 换而言之,对形参执行的任何操作都是对实参执行的。
传递到 ref 或 in 形参的实参必须先经过初始化,然后才能传递。

class Product
{
    public Product(string name, int newID)
    {
        ItemName = name;
        ItemID = newID;
    }

    public string ItemName { get; set; }
    public int ItemID { get; set; }
}

class Program
{
    private static void ChangeByReference(ref Product itemRef)
    {
        // Change the address that is stored in the itemRef parameter.
        itemRef = new Product("Stapler", 99999);

        // You can change the value of one of the properties of
        // itemRef. The change happens to item in Main as well.
        itemRef.ItemID = 12345;
    }

    static void Main(string[] args)
    {
        // Declare an instance of Product and display its initial values.
        Product item = new Product("Fasteners", 54321);
        System.Console.WriteLine("Original values in Main.  Name: {0}, ID: {1}\n",
            item.ItemName, item.ItemID);

        // Pass the product instance to ChangeByReference.
        ChangeByReference(ref item);
        System.Console.WriteLine("Back in Main.  Name: {0}, ID: {1}\n",
            item.ItemName, item.ItemID);
    }
}

引用返回值:
引用返回值(或 ref 返回值)是由方法按引用向调用方返回的值。 即是说,调用方可以修改方法所返回的值,此更改反映在调用方法中的对象的状态中。

  • 在方法签名中。
public ref decimal GetCurrentPrice()
  • 在 return 标记和方法的 return 语句中返回的变量之间。
return ref DecimalArray[0];

ref 局部变量:
ref 局部变量用于指代使用 return ref 返回的值。 无法将 ref 局部变量初始化为非 ref 返回值。 也就是说,初始化的右侧必须为引用。 任何对 ref 本地变量值的修改都将反映在对象的状态中,该对象的方法按引用返回值。

ref decimal estValue = ref Building.GetEstimatedValue();

ref 返回值和 ref 局部变量示例

public class Book
{
    public string Author;
    public string Title;
}

public class BookCollection
{
    private Book[] books = { new Book { Title = "Call of the Wild, The", Author = "Jack London" },
                    new Book { Title = "Tale of Two Cities, A", Author = "Charles Dickens" }
                   };
    private Book nobook = null;

    public ref Book GetBookByTitle(string title)
    {
        for (int ctr = 0; ctr < books.Length; ctr++)
        {
            if (title == books[ctr].Title)
                return ref books[ctr];
        }
        return ref nobook;
    }

    public void ListBooks()
    {
        foreach (var book in books)
        {
            Console.WriteLine($"{book.Title}, by {book.Author}");
        }
        Console.WriteLine();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var bc = new BookCollection();
        bc.ListBooks();

        ref var book = ref bc.GetBookByTitle("Call of the Wild, The");
        if (book != null)
            book = new Book { Title = "Republic, The", Author = "Plato" };
        bc.ListBooks();
    }
}

Out:

out 关键字通过引用传递参数。 它让形参成为实参的别名,这必须是变量。 换而言之,对形参执行的任何操作都是对实参执行的。
若要使用 out 参数,方法定义和调用方法均必须显式使用 out 关键字。
out 参数传递的变量在方法调用中传递之前不必进行初始化。
被调用的方法需要在返回之前赋一个值。

class Program
{
	void OutArgExample(out int number)
	{
	    number = 44;
	}
	
    static void Main(string[] args)
    {
        int initializeInMethod;
		OutArgExample(out initializeInMethod);
		Console.WriteLine(initializeInMethod);     // value is now 44
    }
}

In、Ref 和 Out 关键字不能用于以下几种方法:

  • 异步方法,通过使用 async 修饰符定义。
  • 迭代器方法,包括 yield return 或 yield break 语句。
  • 不能对扩展方法的第一个参数使用 out 关键字。
  • 扩展方法的第一个参数不能有 in 修饰符,除非该参数是结构。
  • 扩展方法的第一个参数,其中该参数是泛型类型(即使该类型被约束为结构。)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉丶城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值