一、值类型和引用类型
1、值类型直接存储其值(存储数据的实际值),而引用类型存储对其值的引用(存储的是它们数据的引用)。
引用类型:基类为Objcet栈空间存放:值类型
堆空间存放:引用类型
- 值类型变量声明后,不管是否已经赋值,编译器为其分配内存。
- 引用类型当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。
- 值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。
- 引用类型的对象总是在进程堆中分配(动态分配)。
二、实参与形参
1、值传递
1.1 值传递–引用类型–ref
ref修饰的是引用类型,而不是值类型,也就是说所存储的是地址
案例1:单个值的值传递-引用传递
using System;
namespace ConsoleApp1
{
//参数的传递
class Program
{
static void Main(string[] args)
{
int a = 10;
int b = 99;
Console.WriteLine("Main方法:a={0} && b={1}", a, b);
Swap(a, b);
Console.WriteLine("Main方法:a={0} && b={1}", a, b);
Swap2(ref a, ref b);
Console.WriteLine("Main方法:a={0} && b={1}", a, b);
}
static void Swap(int a, int b)
{
var temp = a;
a = b;
b = temp;
Console.WriteLine("Swap方法:a={0} && b={1}", a, b);
}
static void Swap2(ref int a, ref int b) # ref int a为主函数a的别名
{
var temp = a;
a = b;
b = temp;
Console.WriteLine("Swap2方法:a={0} && b={1}", a, b);
}
}
}
案例2:数组的值传递
using System;
namespace ConsoleApp1
{
//引用类型参数的传递
class Program
{
static void Main(string[] args)
{
int[] a = { 1, 2, 3 };
AddOne(a);
foreach (var k in a)
{
Console.Write("{0} ",k);
}
Console.WriteLine();
AddOne2(ref a);
foreach (var k in a)
{
Console.Write("{0} ", k);
}
Console.ReadLine();
}
static void AddOne(int[] a)
{
for (int i = 0; i < a.Length; i++)
{
a[i]++;
}
}
static void AddOne2(ref int[] a)
{
a = new int[4] { 11, 12, 13, 14 };
for (int i = 0; i < a.Length; i++)
{
a[i]++;
}
}
}
}
1.2、out可以向方法传递一个未赋初值的实参。
using System;
namespace ConsoleApp1
{
//引用类型参数的传递
class Program
{
static void Main(string[] args)
{
int v1 = 1;
int v2 = 3;
AddAndSub(v1, v2, out int v3, out int v4);
Console.WriteLine("v3={0}", v3);
Console.WriteLine("v4={0}", v4);
}
static void AddAndSub(int v1,int v2,out int v3,out int v4)
{
v3 = v1 + v2;
v4 = v1 - v2;
}
}
}
区分:ref有进有出,out无进有出
三、方法重载
using System;
namespace ConsoleApp1
{
//引用类型参数的传递
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Average(1));
Console.WriteLine(Average(1, 2, 3, 4));
}
static double Average(params int[] a)
{
int b = a.GetLength(0);
double s = 0;
foreach (int k in a)
{
s += k;
}
return s / b;
}
}
}
在使用数组作为形参时,C# 提供了 params 关键字,使调用数组为形参的方法时,既可以传递数组实参,也可以传递一组数组元素。
1.带params关键字的数组形参,既可以接受数组(直接传数组名,应该是地址),也可以接受多个和形参同类型的值(不是数组形式),如有方法 public int test (params int [] array), int [] a=new int [2] 作为数组时可以 test(a) 来调用,也可以 test(1,2,3,4) 来调用。
2.不带params关键字的数组形参,如方法public int test (int [] array),不通过传值的方式调用,只能传数组的方式调用。
using System;
namespace ConsoleApp1
{
//方法的重载
class Program
{
static void Main(string[] args)
{
var area = TriangleArea(3d, 4d, 5d);
Console.WriteLine(area);
area = TriangleArea(3, 4, Math.PI / 2);
//3,4默认为int类型
Console.WriteLine(area);
area = TriangleArea(3, 4);
Console.WriteLine(area);
}
//S公式法
static double TriangleArea(double a, double b, double c)
{
var s = (a + b + c) / 2;
return Math.Sqrt(s * (s - a) * (s - b) * (s - c));
}
//S=1/2*底*高
static double TriangleArea(double a, double h)
{
return (a * h) / 2;
}
//三角函数求面积
static double TriangleArea(int a, int b, double theta)
{
return (a * b * Math.Sin(theta)) / 2;
}
}
}
参考
https://www.icourse163.org/learn/XJTU-1002843011?tid=1450232477&from=study#/learn/content?type=detail&id=1214491025&sm=1