C#数据类型
一、值参数
声明时,不带修饰符的形参是值形参。
- 值类型
注意:- 值参数创建变量的副本
- 对值参数的操作永远不改变变量的值
class Program
{
static void Main(string[] args)
{
Student student = new Student();
int y = 100;
student.AddOne(y);
Console.WriteLine("y:{0}", y);//输出y:100
}
}
class Student
{
public void AddOne(int x)//int x 为值参数
{
x = x + 1;
Console.WriteLine("x:{0}", x);//输出x:101
}
}
- 引用类型,并且新创建对象
注意:
- 值参数创建变量的副本
- 对值参数的操作永远不改变变量的值
class Program
{
static void Main(string[] args)
{
Student student1 = new Student() { Name = "Tim" };
SomeMethod(student1);
Console.WriteLine("{0},{1}", student1.GetHashCode(), student1.Name);//输出18543596,Tim
}
static void SomeMethod(Student stu)
{
stu = new Student() { Name = "Tom" };
Console.WriteLine("{0},{1}",stu.GetHashCode(), stu.Name);//输出54267293,Tom
}
}
class Student
{
public string Name { get; set; }
}
- 引用类型,只操作对象,不创建对象(传递的是执行对象的地址)
class Program
{
static void Main(string[] args)
{
Student student1 = new Student() { Name = "Tim" };
Console.WriteLine("{0},{1}", student1.GetHashCode(), student1.Name);//54267293,Tim
UpdateObject(student1);
Console.WriteLine("{0},{1}", student1.GetHashCode(), student1.Name);//54267293,Tom
}
static void UpdateObject(Student stu)
{
stu.Name = "Tom";
Console.WriteLine("{0},{1}", stu.GetHashCode(), stu.Name);//输出54267293,Tom
}
}
class Student
{
public string Name { get; set; }
}
二、引用参数
引用参数是用ref
修饰符声明的形参。与值形参不同,引用形参并不创建新的存储位置。相反,引用形参表示的存储位置恰是在方法调用中作为实参给出的那个变量的存储位置。
- 值类型
注意:
- 引用参数并不创建变量的副本,都指向一个地址。
- 使用ref修饰符显示指出——此方法的副作用是改变实际参数的值。
class Program
{
static void Main(string[] args)
{
int y = 1;
SideEffect(ref y);
Console.WriteLine("y:{0}",y);//输出 y:101
}
static void SideEffect(ref int x) {
x = x + 100;
Console.WriteLine("x:{0}", x);//输出 x:101
}
}
- 引用类型,创建新对象
class Program
{
static void Main(string[] args)
{
Student student1 = new Student() { Name = "Tim" };
Console.WriteLine("{0},{1}", student1.GetHashCode(), student1.Name);//54267293,Tim
SideEffect(ref student1);
Console.WriteLine("{0},{1}", student1.GetHashCode(), student1.Name);//18643596,Tom
}
static void SideEffect(ref Student stu)
{
stu = new Student() { Name = "Tom" };
Console.WriteLine("{0},{1}", stu.GetHashCode(), stu.Name);//18643596,Tom
}
}
class Student
{
public string Name { get; set; }
}
- 引用类型,不创建新对象只改变对象值
class Program
{
static void Main(string[] args)
{
Student student1 = new Student() { Name = "Tim" };
Console.WriteLine("{0},{1}", student1.GetHashCode(), student1.Name);//54267293,Tim
SideEffect(ref student1);
Console.WriteLine("{0},{1}", student1.GetHashCode(), student1.Name);//54267293,Tom
}
static void SideEffect(ref Student stu)
{
stu.Name = "Tom";
Console.WriteLine("{0},{1}", stu.GetHashCode(), stu.Name);//54267293,Tom
}
}
class Student
{
public string Name { get; set; }
}
三、输出参数
用out修饰符声明的形参是输出形参。输出形参不创建新的存储位置。输出形参表示的存储位置就是方法调用中作为实参给出的那个变量所表示的存储位置。
- 值类型
-
输出参数并不创建变量的副本
-
方法体内必须有对输出变量的赋值
-
使用out修饰符显示指出——此方法的副作用是通过参数向外输出值
static void Main(string[] args) { Console.WriteLine("Please input first number:"); string str1 = Console.ReadLine(); double x = 0; bool b1 = double.TryParse(str1, out x); if (b1 == false) { Console.WriteLine("Input error"); return; } Console.WriteLine("Please input second number:"); string str2 = Console.ReadLine(); double y = 0; bool b2 = double.TryParse(str2, out y); if (b2 == false) { Console.WriteLine("Input error"); return; } double z = x + y; Console.WriteLine("{0}+{1}={2}",x,y,z); }
-
class Program
{
static void Main(string[] args)
{
double x = 0;
bool b = DoubleParse.TryParse("789", out x);
if (b) {
Console.WriteLine(x+1);
}
}
}
class DoubleParse
{
//声明一个带有输出参数的函数
public static bool TryParse(string input, out double result)
{
try
{
result = double.Parse(input);
return true;
}
catch
{
result = 0;
return false;
}
}
}
- 引用类型
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
bool b = StudentFactory.Create("Tom", 20, out stu);
if (b)
{
Console.WriteLine("student {0}, age is {1}", stu.Name, stu.Age);
}
}
}
class Student
{
public string? Name { get; set; }
public int Age { get; set; }
}
class StudentFactory
{
public static bool Create(string stuName, int stuAge, out Student result)
{
result = new Student();
if (string.IsNullOrEmpty(stuName))
{
return false;
}
if (stuAge < 20 || stuAge > 80)
{
return false;
}
result = new Student() { Name = stuName, Age = stuAge };
return true;
}
}
四、数组参数
必须是形参列表的最后一个,只能有一个,由params
修饰。例如 String.Format
和String.Split
方法
string str = "Time;Tom,Amy.Lisa";
string[] result = str.Split(';', ',', '.');
foreach (string s in result)
{
Console.WriteLine(s);
}
static void Main(string[] args)
{
int result = CaculateSum(1, 2, 3);
Console.WriteLine(result);
}
static int CaculateSum(params int[] intArray)
{
int sum = 0;
foreach (int i in intArray)
{
sum += i;
}
return sum;
}
五、具名参数
static void Main(string[] args)
{
PrintInfo(name: "Tim", age: 34);//输出Hello Tim, you are 34
}
static void PrintInfo(string name, int age) {
Console.WriteLine("Hello {0}, you are {1}",name,age);
}
优点:
- 提高代码的可读性
- 参数位置不受参数顺序的约束
六、可选参数
参数因为具有默认值而变得“可选”
不推荐使用可选参数
static void Main(string[] args)
{
PrintInfo();//输出Hello Tim, you are 34
}
static void PrintInfo(string name ="Tim", int age = 34) {
Console.WriteLine("Hello {0}, you are {1}",name,age);
}
七、扩展参数(this参数)
为目标数据类型追加方法
- 方法必须是公有的、静态的,即被
public static
修饰 - 必须是形参列表的第一个,由
this
修饰 - 必须由一个静态类(一般类名为SomeTypeExtension)来统一收纳对SomeType类型的扩展方法
class Program
{
static void Main(string[] args)
{
double x = 3.14159;
double y = x.Round(4);
Console.WriteLine(y);//输出3.1416
}
}
static class DoubleExtension
{
public static double Round(this double input, int digits)
{
double result = Math.Round(input, digits);
return result;
}
}
using System.Linq;
namespace PropertyExample
{
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>() { 11,12,13,14,15};
bool result = list.All(i => i > 10);
Console.WriteLine(result);//输出True
}
}
}
各种参数的使用场景总结
- 传值参数:参数的默认传递方式
- 输出参数:用于除返回值外还需输出的场景
- 引用参数:用于需要修改实际参数值
- 数组参数:用于简化方法的调用
- 具名参数:提供可读性
- 可选参数:参数拥有默认值
- 扩展参数(this参数):为目标数据类型追加方法