C#中有关函数的知识
函数的签名
由函数的名称和参数共同定义,简单地说,签名由方法名称、它的参数类型和参数的修饰符组成。方法的签名不包括返回类型,并且不包括参数的名称。例:void F();//签名是F(),int F(int x);//签名是F(int),int F(out int x);//签名是F(out int),此处out指的是参数的修饰符。
一般采用PascalCase来编写函数名
执行一行代码的函数可以使用C#6引入的一个功能:表达式体方法。使用=>(Lamada箭头)来表示它。例如
static double Multiply(double myVal1,double myVal2)
{
return myVal1*myVal2;
}
在C# 6之后就可以使用=>来编写
static double Multiply(double myVal1,double myVal2)=>myVal1*myVal2;
参数数组
C#允许为函数指定一个(只能指定一个)特殊数组,这个参数必须是函数定义的最后一个参数,称为参数数组。参数数组允许使用个数不定的参数来调用函数,可以使用params关键字来定义他们。参数数组可以简化代码,因为在调用代码时可以不必传递数组,而是传递同类型的几个参数,这些参数会放在可在函数中使用的一个数组之中。
static <returnType> <FunctionName>(params <type>[] <name>)
{
return <returnValue>
}
例子如下:
static int SumVals(params int[] vals)
{
int sum = 0;
foreach (int val in vals)
{
m += val;
}
return sum;
}
static void Main(string[] args)
{
int sum = SumVals(1, 5, 2, 9, 8);
WriteLine($"Summed Values = {sum}");
ReadKey();
}
通过引用传递参数
通过引用传递参数,即函数处理的变量与函数调用中使用的变量相同,而不仅仅时值相同的变量,因此对这个变量进行的任何改变都会影响用作参数的变量值,为此只要使用ref关键字指定关键字
static void ShowDouble(ref int val)
{
val *=2;
WriteLine($"val doubled = {val}");
}
在调用中指定它
int myNumber = 5;
WriteLine($"myNumber = {myNumber}");
ShowDouble(ref muNumber);
WriteLine($"myNumber = {muNumber}");
这时得到的结果为
myNumber=5;
val doubled=10;
myNumber=10;
在使用ref参数时有两个限制,首先函数可能会改变引用参数的值,所以必须在函数调用中使用非常量的变量。第二必须使用初始化的变量,C#不允许假定ref参数在使用他的函数中初始化。
ref 变量也可以用于局部变量和返回值
输出参数
除了按引用传递值之外还可以使用out关键字,out关键字指定的参数是个输出参数,out关键字的使用方法与ref关键字相同,其执行方式与引用的参数几乎完全一模一样,在函数执行完毕之后,该参数的值将返回给函数调用中使用的变量。但是ref和out之间存在一些重要的区别。
1、未赋值的变量用作ref参数时非法的,但可以把未赋值的变量用作out参数,
2、函数在使用out参数时,必须把他看成时尚未赋值的。
out关键字旨在通过引用传递参数,而不必实现初始化它。
元组
从函数中返回多个值有多种方法,例如使用out关键字(虽然这并不是out关键字的本义),使用结构或数组,元组提供了一种非常优雅的方法以较小开销返回多个值。创建一个名为numbers的元组
var numbers = {1,2,3,4,5};
其中包含成员Item1,Item2,Item3,Item4和Item5,可采用下面的这种方式来访问这些成员。
var number = numbers.Item1//后续将会继续补充
结构函数
结构函数就是将函数添加到结构中间例如
struct CustomerName
{
public string firstName,LastName;
public string Name()=>firstName + " " + lastName;
}
//使用时
CustomerName myCustomer;
myCustomer.firstName="John";
myCustomer.lastName="Franklin";
WriteLine(myCustomer.Name());
函数重载
函数重载允许创建多个同名函数,每个函数可使用不同的参数类型。
函数委托
委托是一种存储函数引用的类型, 委托的声明类似于函数,但不带函数体,且要使用delegate关键字,委托的申明指定了一个返回类型和一个参数列表。定义了委托后,就可以声明该委托类型的变量,接着把这个变量初始化为与委托具有相同返回类型和参数列表的函数引用。之后就可以使用委托变量调用这个函数,就像该变量是一个函数一样。
有了引用函数的变量后,就可以执行无法用其他方式完成的操作,例如可以把委托变量 作为参数传递给一个函数,这样函数就可以使用委托调用它引用的任何函数,而且在运行之前不必知道调用的是哪个函数。
delegate double ProcessDelegate(double param1, double param2);
static double Multiply(double param1, double param2) => param1 * param2;
static double Divide(double param1, double param2) => param1 / param2;
static void Main(string[] args)
{
ProcessDelegate process;
WriteLine("Enter 2 numbers separated with a comma:");
string input = ReadLine();
int commaPos = input.IndexOf(',');
double param1 = ToDouble(input.Substring(0, commaPos));
double param2 = ToDouble(input.Substring(commaPos + 1,input.Length - commaPos - 1));
WriteLine("Enter M to multiply or D to divide:");
input = ReadLine();
if (input == "M")
process = new ProcessDelegate(Multiply);
else
process = new ProcessDelegate(Divide);
WriteLine($"Result: {process(param1, param2)}");
ReadKey();
}
这段代码定义了一个委托ProcessDelegate,其返回类型和参数与函数Multiply()和和Divide()相匹配,这里的用法是把委托直接当作函数名来使用,其实委托也可以用作函数的参数来使用,将委托作为形参函数名作为实参来使用委托。具体例子如下
static void ExecuteFunction(ProcessDelegate process)
=> process(2.2,3.3);
例二
public delegate void MyDelegate(string str);//声明一个没有参数没有返回值的委托函数
class Program
{
static void Main(string[] args)
{
HandleStr("hello world", StrToUppper);
HandleStr("HELLO WORLD", StrToLower);
System.Console.ReadLine();
}
static void HandleStr(string str ,MyDelegate del)
//委托作函数参数,有点多态的意识
{
del(str);//委托的调用
}
static void StrToUppper(string str)//将字符串转成大小
{
str = str.ToUpper();
System.Console.WriteLine(str);
}
static void StrToLower(string str) //将字符串转换成小写
{
str = str.ToLower();
System.Console.WriteLine(str);
}
}
}//这段代码引用自其实我不胖_csdn同学
就像选择一个要使用的插件一样,通过把函数委托传递给函数,就可以控制函数的执行。委托还有许多哟用途,主要和事件处理有关。后续会加上。