C# -- ref / out / params

转载自:https://blog.csdn.net/u011555996/article/details/52871908

-----------------------

1.ref/out

ref和out都对函数参数采用引用传递形式——不管是值类型参数还是引用类型参数,并且定义函数和调用函数时都必须显示生命该参数为ref/out形式。两者都可以使函数传回多个结果。

两者区别:

两种参数类型的设计思想不同,(1)ref的目的在于将值类型参数当作引用型参数传递到函数,是函数的输入参数,并且在函数内部的任何改变也都将影响函数外部该参数的值;(2)而out的目的在于获取函数的返回值,是输出参数,由函数内部计算得到的值再回传到函数外部,因此必须在函数内部对该参数赋值,这将冲掉函数外部的任何赋值,使得函数外部赋值毫无意义。

表现为:

1、out必须在函数体内初始化,这使得在外面初始化变得没意义。也就是说,out型的参数在函数体内不能得到外面传进来的初始值。
2、ref必须在函数体外初始化。
3、两者在函数体内的任何修改都将影响到函数体外面。

例:

using System;
namespace ConsoleApplication1{
	class C{
		public static void reffun(ref string str)
		{
			str += " fun";
		}

		public static void outfun(out string str)
		{
			str = "test"; //必须在函数体内初始, 如无此句,则下句无法执行,报错
			str += " fun";
		}
}

class Class1
{
	[STAThread]
	static void Main(string[] args)
		{
		string test1 = "test";
		string test2; //没有初始
		C.reffun( ref test1 ); //正确
		C.reffun( ref test2 ); //错误,没有赋值使用了test2
		C.outfun( out test1 ); //正确,但值test无法传进去
		C.outfun( out test2 ); //正确

		Console.Read();
		}
	}
}

[注意]:out 关键字,并不是为了作为函数的返回值,而是为了把被call函数内部的某个变量带回caller函数内部。详细看下面的例子:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("主程序开始--------------------");
        int threadId;
        AsyncDemo ad = new AsyncDemo();
        AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

        IAsyncResult result = caller.BeginInvoke(3000,out threadId, null, null);
        Thread.Sleep(0);
        Console.WriteLine("主线程线程 {0} 正在运行.",Thread.CurrentThread.ManagedThreadId)
        //会阻塞线程,直到后台线程执行完毕之后,才会往下执行
        result.AsyncWaitHandle.WaitOne();
        Console.WriteLine("主程序在做一些事情!!!");
        //获取异步执行的结果
        string returnValue = caller.EndInvoke(out threadId, result);
        //释放资源
        result.AsyncWaitHandle.Close();
        Console.WriteLine("主程序结束--------------------");
        Console.Read();
    }
}
public class AsyncDemo
{
    //供后台线程执行的方法
    public string TestMethod(int callDuration, out int threadId)
    {
        Console.WriteLine("测试方法开始执行.");
        Thread.Sleep(callDuration);
        threadId = Thread.CurrentThread.ManagedThreadId;
        return String.Format("测试方法执行的时间 {0}.", callDuration.ToString());
    }
}
public delegate string AsyncMethodCaller(int callDuration, out int threadId);

这里的参数使用了out,在此之前只做了声明没有初始化。为了从被call函数获得值,这里的参数用到了out。

int threadId;

IAsyncResult result = caller.BeginInvoke(3000,out threadId, null, null);

在TestMethod()内部,专门为treadId赋值,该值会被带回caller函数。

public string TestMethod(int callDuration, out int threadId)
    {
        Console.WriteLine("测试方法开始执行.");
        Thread.Sleep(callDuration);
        threadId = Thread.CurrentThread.ManagedThreadId;
        return String.Format("测试方法执行的时间 {0}.", callDuration.ToString());
    }



2.params

params 关键字可以指定在参数数目可变处采用参数的方法参数。

在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。

The params keyword lets you specify a method parameter that takes an argument where the number of arguments is variable.

No additional parameters are permitted after the params keyword in a method declaration, and only one params keyword is

permitted in a method declaration.

// cs_params.cs
using System;
public class MyClass
{
	public static void UseParams(params int[] list)
	{
		for (int i = 0 ; i < list.Length; i++)
		{
			Console.WriteLine(list[i]);
		}
		Console.WriteLine();
	}

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

	static void Main()
	{
		UseParams(1, 2, 3);
		UseParams2(1, 'a', "test");

		// An array of objects can also be passed, as long as
		// the array type matches the method being called.
		int[] myarray = new int[3] {10,11,12};
		UseParams(myarray);
	}
}


Output

1
2
3

1
a
test

10
11
12

猜你喜欢

转载自blog.csdn.net/u011144776/article/details/80825194