C# 是由微软(Microsoft)开发的,基于C和C++的一种面向对象的编程语言,其语法规则十分类似于Java,常用于快速开发Windows桌面应用。本文将对C# 的一些基础语法知识进行快速学习,快速上手。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace netBasic_learning
{
//类的定义
class Rectangle
{
//(1)属性
double length;
double width;
//(2)方法
public void Acceptdetails()
{
this.length = 4.5;
this.width = 2;
}
public double getArea()
{
return this.length * this.width;
}
public void Display()
{
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", getArea());
}
//Main函数是程序的主入口
public static void Main(string[] args)
{
Rectangle rectangle = new Rectangle();
rectangle.Acceptdetails();
rectangle.Display();
//阻塞窗口
Console.ReadLine();
}
}
}
1.using的使用:
(1)含义:使用命名空间,类似于Java的Import
(2)注意:using 关键字用于在程序中包含命名空间。一个程序可以包含多个 using 语句。2.namespace的使用:
(1)namespace声明本类的命名空间为netBasic_learning,其他地方可以通过using netBasic_learning来使用此处的类和方法
(2)一个namespace内可以包含多个类3.Main函数的阻塞:
(1)Console.ReadLine() : 最后一行 Console.ReadLine(); 是针对 VS.NET 用户的。这使得程序会等待一个回车的动作,防止程序从 Visual Studio .NET 启动时屏幕会快速运行并关闭。即防止黑窗口一闪而过,阻塞一下。同时ReadLine()方法还可以用于读取程序输入。 (2)Console.ReadKey() : 其作用同上。
4.总结:
1.C#语法基本与Java差不多,都是面向对象的语言。只不过C#主要面向桌面应用开发,Java主要面向Web应用开发
2.C#与 Java 不同的是,文件名可以不同于类的名称。
namespace netBasic_learning
{
class Basic_dataType
{
public static void Main(String[] args)
{
//1.基本数据类型:分配存储空间,存放数据
int Int_number = 1;
double Double_number = 3.14;
bool Bool_number = true;
Console.WriteLine("Int: {0},Double: {1},Bool: {2}", Int_number,Double_number,Bool_number);//自动换行
}
}
}
引用类型不包含存储在变量中的实际数据,但它们包含对变量的引用。换句话说,它们指的是一个内存位置。使用多个变量时,引用类型可以指向一个内存位置。如果内存位置的数据是由一个变量改变的,其他变量会自动反映这种值的变化。内置的 引用类型有:object、string和我们自定义的类Class。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace netBasic_learning
{
class Basic_dataType
{
public static void Main(String[] args)
{
//引用数据类型:存放数据的引用地址,即别名(Object、String、class)
String str = "Hello World!";
String str_origin = "Hello\nWorld!";//转义字符
String str_change = @"Hello\nWorld!";//原样输出 @ = "\\"
Console.WriteLine("String str: {0}", str);
Console.WriteLine("String str_origin: {0}", str_origin);
Console.WriteLine("String str_change: {0}", str_change);
}
}
}
一.数据类型转换
(1)隐式类型转换:安全转换,不会造成数据丢失。比如从派生类转换为基类,小范围类型->大范围类型int->long,float->double,在一些计算中会自动转换发生
(2)显式类型转换:不安全转换,可能会造成数据丢失。比如double->int(3)内置的类型转换方法:int.Parse()、ToString()等
namespace netBasic_learning
{
class Basic_dataType
{
public static void Main(String[] args)
{
//数据类型转换
// (1)隐式类型转换:安全转换,不会造成数据丢失。比如从派生类转换为基类,小范围类型->大范围类型int->long,float->double,在一些计算中会自动转换发生
// (2)显式类型转换:不安全转换,可能会造成数据丢失。比如double->int
double a = 3.1415;
int b = (int)a;//向下取整,丢失精度
Console.WriteLine("Double->Int: {0}", b);
// (3)内置的类型转换方法
string num = "66";
Console.WriteLine("Int -> String: {0}",a.ToString());
Console.WriteLine("String -> Int: {0}", int.Parse(num));
//4.常量:const ,运行期间不能被修改
Console.ReadLine();
}
}
}
一.字符串:使用 string 关键字来声明一个字符串变量。string 关键字是 System.String 类的别名。
1.字符串构建:
- "":string str = "hello world!";
- +:string str = a + b;(字符串拼接)2.字符串常用方法:
- public static int Compare( string strA, string strB ):比较两个指定的 string 对象(按ASCII),并返回一个表示它们在排列顺序中相对位置的整数。
- public static string Concat( string str0, string str1 ):连接两个 string 对象。相当于+
- public bool Contains( string value ):判断字符串是否包含字串value
- public bool EndsWith( string value ):判断 string 对象是否以value结尾。
- public bool StartsWith( string value ):判断字符串实例的开头是否匹配指定的字符串。
- public bool Equals( string value ):判断当前的 string 对象是否与指定的 string 对象具有相同的值。
- public static string Format( string format, Object arg0 ):把指定字符串中一个或多个格式项替换为指定对象的字符串表示形式。
- public int IndexOf( string value/char ch ):返回指定字符串在该实例中第一次出现的索引,索引从 0 开始。
- public int LastIndexOf( string value/char value ):返回指定字符串在该实例中最后一次出现的索引,索引从 0 开始。
- public string Insert( int startIndex, string value ):返回一个新的字符串,其中,指定的字符串被插入在当前 string 对象的指定索引位置。
- public static string Join( string separator, string[] value ):连接一个字符串数组中的所有元素,使用指定的分隔符分隔每个元素。
- public string Remove( int startIndex ):移除当前实例中的所有字符,从指定位置开始,一直到最后一个位置为止,并返回字符串。
- public string Replace( string oldValue, string newValue ):把当前 string 对象中,所有指定的字符串替换为另一个指定的字符串,并返回新的字符串。
- public string[] Split( params char[] separator ):返回一个字符串数组,包含当前的 string 对象中的子字符串,子字符串是使用指定的 Unicode 字符数组中的元素进行分隔的。
- public char[] ToCharArray():返回一个带有当前 string 对象中所有字符的 Unicode 字符数组。
- public string ToLower()/ToUpper()/Trim()
namespace netBasic_learning
{
class Basic_string
{
public static void mains(string[] args)
{
// (1)字符串构建:
string a_str = "Hello,";
string b_str = "World!,Write the code,change the world.";
string strs = a_str + b_str;
Console.WriteLine(strs);
/**
*(2)字符串方法、操作(重点):
*/
//2.字符串比较
string c_str = "Hello,";
if(a_str == c_str)//==在引用数据里,比较的是地址。因此两个数据相同的变量可能是“不相等的”。
{
//但是此处是相等的,原因是string是常量,地址也相同。
Console.WriteLine("== 比较符号:a_str 与 c_str 相同");
}
if (a_str.Equals(c_str))//Equals比较的是数值大小是否相同,推荐!
{
Console.WriteLine("Equals 比较函数:a_str 与 c_str 相同");
}
int res = String.Compare(a_str, b_str);//a_strb_str是>0
Console.WriteLine("排序结果: {0}",res);
//2.字符串包含
if (strs.Contains("World"))
{
Console.WriteLine("{0}包含{1}", strs,"World");
}
//3.字串获取
string child_str = strs.Substring(15);
Console.WriteLine(child_str);
//4.字符串合并
string[] str_arrays = { "hello", "world", "i'm", "OK" };
string join_str = String.Join("-", str_arrays);
Console.WriteLine(join_str);
//5.字符串分割
string[] str_list = join_str.Split('-');
foreach(string factor in str_list)
{
Console.WriteLine(factor);
}
//6.字符串格式化
Console.ReadKey();
}
}
}
1.算术运算符:+、-、*、/、%、++、--
2.关系运算符:==、!=、>、<、>=、<=
3.逻辑运算符:&&、||、!
4.位运算:&(与,全1才1)、|(或,一1即1)、^(异或,相异即1)、<<(左移,右补0)、>>(右移,左补0)
5.赋值运算符:+=、-=、/=、%=、&=、<<=
6.其他运算符:
(1)?: 三元表达式 a==1?xxx:yyy
(2)& 取地址
(3)* 指针
(4)sizeof、typeof、is
namespace netBasic_learning
{
class Basic_calculate
{
public static void Main(string[] args)
{
//算术运算
double y = 5 / 2; //如果/法都为整数,则运算结果也为整数(向下取整)
double y_2 = 5.0/2;//如果/法有一个为浮点数,则运算结果自动向大类型转换
Console.WriteLine(y);
Console.WriteLine(y_2);
//总结:运算与Java差不多-。-
Console.ReadLine();
}
}
}
一.条件判断:
(1)if...else if...else
(2)switch(Expression){
case condition1:
break;
case condition2:
break;
default:
}
namespace netBasic_learning
{
class Basic_calculate
{
public static void Main(string[] args)
{
double y = 5 / 2; //如果/法都为整数,则运算结果也为整数(向下取整)
//条件判断:
if (y>0)
{
Console.WriteLine("y > 0");
}else if (y == 0)
{
Console.WriteLine("y = 0");
}
else
{
Console.WriteLine("y < 0");
}
Console.ReadLine();
}
}
}
一.循环语句
(1) for:for(初始化,判断,循环操作){循环语句}、foreach()
(2) while:只要给定的条件为真,会重复执行一个目标语句。先判断再执行
(3)do..while:在循环的尾部检查它的条件。会确保至少执行一次循环。
(4)循环控制语句:break跳出循环,continue直接继续循环
namespace netBasic_learning
{
class Basic_calculate
{
public static void Main(string[] args)
{
//循环语句
// (1)for:for(初始化,判断,循环操作){循环语句}
// (2)while:只要给定的条件为真,会重复执行一个目标语句。先判断再执行
// (3)do..while:在循环的尾部检查它的条件。会确保至少执行一次循环。
// (4)循环控制语句:break跳出循环,continue直接继续循环
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
Console.ReadLine();
}
}
}
1.可空类型(null):可空类型可以表示其基础值类型正常范围内的值,再加上一个 null 值。
(1)声明可空类型:
- 基本数据:? 单问号用于对 int、double、bool 等无法直接赋值为 null 的数据类型进行 null 的赋值。比如:int? num1 = null;
- 类与对象:直接声明(2)null合并运算符(??):判断如果第一个操作数的值为 null,则运算符返回第二个操作数的值,否则返回第一个操作数的值。
- 使用:a = b ?? c
- 本质:a = (b==null)?c:b
namespace netBasic_learning
{
class Basic_Arrays
{
public static void Main(string[] args)
{
//1.可空类型(null):可空类型可以表示其基础值类型正常范围内的值,再加上一个 null 值。
// (1)声明可空类型:
int? num1 = null;//可空int类型取空值
int? num2 = 66;//可空int类型不取空值
double? num3 = null;
double? num4 = 3.1415;
Console.WriteLine("显示可空类型的值: {0}, {1}, {2}, {3}",num1, num2, num3, num4);
if(num1 == null)//空值判断
{
Console.WriteLine("Int数据num1为空值");
}
Rectangle rect = null;//类&对象空值声明
if(rect == null)//类&对象空值判断
{
Console.WriteLine("Rectangle类对象rect为空");
}
// (2)null合并运算符(??):判断如果第一个操作数的值为 null,则运算符返回第二个操作数的值,否则返回第一个操作数的值。
double? b = null;
double? c = 3.1415;
double? a = b ?? c;//b如果为空则返回c
Console.WriteLine("a 的值: {0}", a);
Console.ReadKey();
}
}
}
1.数组:数组是一个存储【相同类型元素】的固定大小的顺序集合
(1)声明数组:double[] arrays; 声明一个数组不会在内存中初始化数组。
(2)初始化数组:double[] balance = new double[10];数组是一个引用类型,所以您需要使用 new 关键字来创建数组的实例。
(3)数组赋值:
- 索引赋值: balance[0] = 3.14;
- 声明数组的同时给数组赋值: double[] balance = { 2340.0, 4523.69, 3421.0};
- 创建并初始化一个数组: int [] marks = new int[5] { 99, 98, 92, 97, 95};
- 省略数组的大小:int [] marks = new int[] { 99, 98, 92, 97, 95};
- 赋值一个数组变量到另一个目标数组变量中。在这种情况下,目标和源会指向相同的内存位置(引用):int[] score = marks;
(4)数据访问、遍历:[]下标访问+for、foreach循环(5)多维数组:int[,] a;声明二维数组,int[, ,] a;声明三维数组
(6)交错数组:交错数组是数组的数组。交错数组是一维数组,每个元素是一个数组
- 声明:int [][] scores;int数组的一维数组,声明一个数组不会在内存中创建数组
- 初始化:int[][] scores = new int[5][];含有五个元素
- 初始化赋值:int[][] scores = new int[2][]{new int[]{92,93,94},new int[]{85,66,87,88}};
- 访问:scores[i][j] 取第i个子数组的第j个元素(类似于二维数组)
namespace netBasic_learning
{
class Basic_Arrays
{
public static void Main(string[] args)
{
//1.数组:数组是一个存储【相同类型元素】的固定大小的顺序集合
// (1)声明数组:double[] arrays; 声明一个数组不会在内存中初始化数组。
// (2)初始化数组:double[] balance = new double[10];数组是一个引用类型,所以您需要使用 new 关键字来创建数组的实例。
// (3)数组赋值:
// - 索引赋值: balance[0] = 3.14;
// - 声明数组的同时给数组赋值: double[] balance = { 2340.0, 4523.69, 3421.0};
// - 创建并初始化一个数组: int [] marks = new int[5] { 99, 98, 92, 97, 95};
// - 省略数组的大小:int [] marks = new int[] { 99, 98, 92, 97, 95};
// - 赋值一个数组变量到另一个目标数组变量中。在这种情况下,目标和源会指向相同的内存位置(引用):int[] score = marks;
// (4)数据访问、遍历:[]下标访问+for、foreach循环
int[] List = new int[10];
for(int i = 0; i < List.Length; i++)
{
List[i] = i*2;
}
foreach(int j in List)
{
Console.WriteLine("Element = {0}",j);
}
// (4)多维数组:int[,] a;声明二维数组,int[, ,] a;声明三维数组
int[,] matrix = new int[3, 4];//初始化3x4的二维数组
int[,] matrix_2 = new int[3, 4]{//初始化并赋值
{0,1,2,3 }, //初始化第0行
{4,5,6,7}, //初始化第1行
{8,9,10,11} //初始化第2行
};
for(int i = 0; i < matrix_2.GetLength(0); i++)//循环遍历多维数组
{
for(int j = 0; j < matrix_2.GetLength(1); j++)
{
Console.WriteLine("矩阵({0},{1})的值为{2}", i,j, matrix_2[i,j]);
}
}
// (5)交错数组:交错数组是数组的数组。交错数组是一维数组,每个元素是一个数组
// - 声明:int [][] scores;int数组的一维数组,声明一个数组不会在内存中创建数组
// - 初始化:int[][] scores = new int[5][];含有五个元素
// - 初始化赋值:int[][] scores = new int[2][]{new int[]{92,93,94},new int[]{85,66,87,88}};
// - 访问:scores[i][j] 取第i个子数组的第j个元素(类似于二维数组)
int[][] scores = new int[5][];
for (int i = 0; i < scores.Length; i++)
{
if (i <= 2) scores[i] = new int[3];
else scores[i] = new int[5];
for(int j = 0; j < scores[i].Length; j++)
{
scores[i][j] = i * j + 6;
}
}
for (int i = 0; i < scores.Length; i++)
{
for (int j = 0; j < scores[i].Length; j++)
{
Console.WriteLine("子数组{0}下标{1}的值为{2}", i, j, scores[i][j]);
}
}
Console.ReadKey();
}
}
}
(7)Array 类:Array 类是 C# 中所有数组的基类,提供了很多属性和方法
- Array.Clear:根据元素的类型,设置数组中某个范围的元素为零、为 false 或者为 null。
- Array.IndexOf(Array, Object):搜索指定的对象,返回整个[一维数组]中第一次出现的索引。
- Array.Reverse(Array):逆转整个一维数组中元素的顺序。
- Array.Sort(Array):使用数组的每个元素的 IComparable 实现来排序整个一维数组中的元素。
namespace netBasic_learning
{
class Basic_Arrays
{
public static void Main(string[] args)
{
// (6)Array 类:Array 类是 C# 中所有数组的基类,提供了很多属性和方法
// - Array.Clear:根据元素的类型,设置数组中某个范围的元素为零、为 false 或者为 null。
// - Array.IndexOf(Array, Object):搜索指定的对象,返回整个[一维数组]中第一次出现的索引。
// - Array.Reverse(Array):逆转整个一维数组中元素的顺序。
// - Array.Sort(Array):使用数组的每个元素的 IComparable 实现来排序整个一维数组中的元素。
int[] list = { 34, 72, 13, 44, 25, 30, 10 };
Console.Write("原始数组: ");
foreach (int i in list)
{
Console.Write(i + " ");//不换行输出
}
Console.WriteLine();//输出换行
// 逆转数组
Array.Reverse(list);//改变原数组
Console.Write("逆转数组: ");
foreach (int i in list)
{
Console.Write(i + " ");
}
Console.WriteLine();
// 排序数组
Array.Sort(list);//改变原数组,默认由小到大
Console.Write("排序数组: ");
foreach (int i in list)
{
Console.Write(i + " ");
}
Console.ReadKey();
}
}
}
1.ArrayList:动态数组列表集合,类似于Java的List
namespace netBasic_learning
{
//1.ArrayList:动态数组列表集合,类似于Java的List
2.List:List也是一种动态列表集合,类似于ArrayList,但必须提供泛型
(1)定义:为了解决ArrayList的类型不安全,C#提供了List列表,List列表声明时必须提供泛型,即List内存放的数据必须都是该泛型的数据。
(2)初始化:Listlist = new List ();
(3)本质:List其实就是在ArrayList基础上,添加了类型限制,以后都推荐使用List
(4)使用:与ArrayList类似,注意泛型也可以是自定义的类,List也可以存放对象!
namespace netBasic_learning
{
//2.List:List也是一种动态列表集合,类似于ArrayList,但必须提供泛型
// (1)定义:为了解决ArrayList的类型不安全,C#提供了List列表,List列表声明时必须提供泛型,即List内存放的数据必须都是该泛型的数据。
// (2)初始化:List list = new List();
// (3)本质:List其实就是在ArrayList基础上,添加了类型限制,以后都推荐使用List
// (4)使用:与ArrayList类似,注意泛型也可以是自定义的类,List也可以存放对象!
class List_Use
{
public static void mains(string[] args)
{
List list = new List();
for(int i = 0; i < 10; i++)
{
list.Add(i + 1);
}
for(int i = 0; i < list.Count; i++)
{
if (list[i] % 2!=0)
{
list[i] *= 2;
}
}
foreach(int val in list)
{
Console.Write(val + " ");
}
Console.WriteLine();
list.Clear();
Console.WriteLine("清空后长度 : " + list.Count);
Console.ReadLine();
}
}
}
3.Dictionary:Dictionary是由键值对组成的字典类型,类似于Java的Map
(1)初始化:Dictionary也是对象,需要使用new关键字。同时在初始化时需要指定键值对的泛型 Dictionarydir = new Dictionary ();
(2)特点:
- Dictionary里面的每一个元素都是一个键值对(由二个元素组成:键和值),可以通过 Dictionary[key]来取值
- Dictionary里面键必须是唯一的,而值不需要唯一的
(3)使用:
- Count 获取包含在 Dictionary中的键/值对的数目。
- Keys 获取包含 Dictionary中的键的集合。
- Values 获取包含 Dictionary中的值的集合。
- Add 将指定的键和值添加到字典中。
- Clear 从 Dictionary中移除所有的键和值。
- ContainsKey 确定 Dictionary是否包含指定的键。
- GetEnumerator 返回循环访问 Dictionary的枚举器
- Remove 从 Dictionary中移除所指定的键的值。
namespace netBasic_learning
{
//3.Dictionary:Dictionary是由键值对组成的字典类型,类似于Java的Map
// (1)初始化:Dictionary也是对象,需要使用new关键字。同时在初始化时需要指定键值对的泛型 Dictionary dir = new Dictionary();
// (2)特点:
// - Dictionary里面的每一个元素都是一个键值对(由二个元素组成:键和值),可以通过 Dictionary[key]来取值
// - Dictionary里面键必须是唯一的,而值不需要唯一的
// (3)使用:
// - Count 获取包含在 Dictionary 中的键/值对的数目。
// - Keys 获取包含 Dictionary 中的键的集合。
// - Values 获取包含 Dictionary 中的值的集合。
// - Add 将指定的键和值添加到字典中。
// - Clear 从 Dictionary 中移除所有的键和值。
// - ContainsKey 确定 Dictionary 是否包含指定的键。
// - GetEnumerator 返回循环访问 Dictionary 的枚举器
// - Remove 从 Dictionary 中移除所指定的键的值。
class Dictionary
{
public static void Main(string[] args)
{
Dictionary dictionary = new Dictionary();
dictionary.Add("wangxin", 99);//Add赋值,Add赋值不能添加key重复的项
dictionary["shayuan"] = 100;//=赋值,=赋值可以添加key重复项,会覆盖原始数据
if (dictionary.ContainsKey("wangxin"))//是否包含key
{
Console.WriteLine("Dictionary 长度: " + dictionary.Count);
Console.WriteLine("wangxin is {0}", dictionary["wangxin"]);
dictionary.Remove("wangxin");//删除key
}
if (dictionary.ContainsKey("shayuan"))
{
Console.WriteLine("Dictionary 长度: " + dictionary.Count);
Console.WriteLine("shayuan is {0}", dictionary["shayuan"]);
}
//Console.WriteLine("wangxin is {0}", dictionary["wangxin"]);//访问不存在的数据会报异常
if (!dictionary.ContainsKey("wangxin"))
{
Console.WriteLine("wangxin is removed!");
}
//遍历Dictionary
//遍历key
foreach (string key in dictionary.Keys)
{
Console.WriteLine("Key = {0}", key);
}
//遍历value
foreach (int value in dictionary.Values)
{
Console.WriteLine("value = {0}", value);
}
//遍历字典
foreach (KeyValuePair kvp in dictionary)
{
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
}
//添加存在的元素 try...catch..处理异常
try
{
dictionary.Add("txt", 99);
}
catch (ArgumentException)
{
Console.WriteLine("An element with Key = \"txt\" already exists.");
}
Console.ReadKey();
}
}
}
1.类的封装
(1)访问修饰符:类的默认访问标识符是 internal,成员的默认访问标识符是 private。
- public:所有对象都可以访问;
- private:对象本身在对象内部可以访问;
- protected:只有该类对象及其子类对象可以访问
- internal:同一个程序集的对象可以访问;可以被定义在该成员所定义的【应用程序内】的任何类或方法访问。
- protected internal:访问限于当前程序集或派生自包含类的类型。(protected和internal的并集)
(2)方法:类的行为,主要是方法参数的传递方式
- 值传递:这种方式复制参数的实际值给函数的形式参数,实参和形参使用的是两个不同内存中的值。在这种情况下,当形参的值发生改变时,不会影响实参的值
- 引用传递(ref):这种方式复制参数的内存位置的引用给形式参数。这意味着,当形参的值发生改变时,同时也改变实参的值。
- 输出参数(out):这种方式可以返回多个值。传 out 定义的参数进去的时候这个参数在函数内部必须初始化。否则是不能进行编译的。
- 数组传值:可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。
注意:ref 和 out 都是传递数据的地址,正因为传了地址,才能对源数据进行修改。2.类的基本参数
(1)构造函数:初始化对象时自动执行,默认提供一个无参构造 Object(){}
(2)析构函数:销毁对象时自动执行 ~Object(){}
(3)静态成员变量: static 关键字把类成员定义为静态的,静态成员变量属于类,可以在任意地方初始化和使用
(4)静态成员函数:static 关键字把类成员定义为静态的,静态成员变量属于类,静态成员函数只能访问静态变量
namespace netBasic_learning
{
//1.类的封装
// (1)访问修饰符:类的默认访问标识符是 internal,成员的默认访问标识符是 private。
// - public:所有对象都可以访问;
// - private:对象本身在对象内部可以访问;
// - protected:只有该类对象及其子类对象可以访问
// - internal:同一个程序集的对象可以访问;可以被定义在该成员所定义的【应用程序内】的任何类或方法访问。
// - protected internal:访问限于当前程序集或派生自包含类的类型。(protected和internal的并集)
// (2)方法:类的行为,主要是方法参数的传递方式
// - 值传递:这种方式复制参数的实际值给函数的形式参数,实参和形参使用的是两个不同内存中的值。在这种情况下,当形参的值发生改变时,不会影响实参的值
// - 引用传递(ref):这种方式复制参数的内存位置的引用给形式参数。这意味着,当形参的值发生改变时,同时也改变实参的值。
// - 输出参数(out):这种方式可以返回多个值。传 out 定义的参数进去的时候这个参数在函数内部必须初始化。否则是不能进行编译的。
// - 数组传值:可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。
// 注意:ref 和 out 都是传递数据的地址,正因为传了地址,才能对源数据进行修改。
class A
{
public int _a;
public int _b;
//值传递
public void sum(int a,int b)
{
a += b;
Console.WriteLine("值传递函数内求和 a = {0}", a);
}
//引用传递
public void sum(ref int a,ref int b)
{
a += b;
Console.WriteLine("引用传递函数内求和 a = {0}", a);
}
//输出参数
public void sum(int a,int b,out int c)
{
c = a + b;
}
//类/对象传递(对象传值 = 引用传值)
public void swap(A obj)
{
int temp = obj._a;
obj._a = obj._b;
obj._b = temp;
}
//数组传值
public void sumAndClear(int[] arrays)
{
int sum = 0;
for(int i = 0; i < arrays.Length; i++)
{
sum += arrays[i];
arrays[i] = 0;
}
Console.WriteLine("数组求和sum = {0}", sum);
}
public static void Main(string[] args)
{
A a_obj = new A();
//值传递
int a = 3, b = 4;
Console.WriteLine("值传递求和前初始数据a = {0},b = {1}", a,b);
a_obj.sum(a, b);
Console.WriteLine("值传递求和后初始数据a = {0},b = {1}", a, b);
//引用传递
Console.WriteLine("引用传递求和前初始数据a = {0},b = {1}", a, b);
a_obj.sum(ref a, ref b);
Console.WriteLine("引用传递求和后初始数据a = {0},b = {1}", a, b);
//输出参数
int res;
Console.WriteLine("输出参数求和前初始数据a = {0},b = {1}", a, b);
a_obj.sum( a, b,out res);
Console.WriteLine("引用传递求和后初始数据a = {0},b = {1},res = {2}", a, b,res);
//对象传递
a_obj._a = 3;
a_obj._b = 4;
Console.WriteLine("对象传递交换前初始数据a = {0},b = {1}", a_obj._a, a_obj._b);
a_obj.swap(a_obj);
Console.WriteLine("对象传递交换后初始数据a = {0},b = {1}", a_obj._a, a_obj._b);
//数组传递
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.Write("数组传值前: ");
foreach(int fac in arr) Console.Write(fac + " ");
Console.WriteLine();
a_obj.sumAndClear(arr);
Console.Write("数组传值后: ");
foreach (int fac in arr) Console.Write(fac + " ");
Console.ReadLine();
}
}
//2.类的基本参数
// (1)构造函数:初始化对象时自动执行,默认提供一个无参构造 Object(){}
// (2)析构函数:销毁对象时自动执行 ~Object(){}
// (3)静态成员变量: static 关键字把类成员定义为静态的,静态成员变量属于类,可以在任意地方初始化和使用
// (4)静态成员函数:static 关键字把类成员定义为静态的,静态成员变量属于类,静态成员函数只能访问静态变量
class B
{
public static int cnt = 0;
private double val;
public B()
{
val = 0;
cnt++;
Console.WriteLine("第{0}个B,无参构造函数Val = {1}",cnt,val);
}
public B(double _val = 0)
{
val = _val;
cnt++;
Console.WriteLine("第{0}个B,有参构造函数Val = {1}", cnt,val);
}
public double getVal()
{
return this.val;
}
public static int getCntOfB()
{
return cnt;
}
~B()
{
cnt--;
Console.WriteLine("析构函数执行");
}
public static void Main(string[] args)
{
B b_1 = new B();
Console.WriteLine(b_1.getVal());
B b_2 = new B(3.14);
Console.WriteLine(b_2.getVal());
Console.WriteLine(B.getCntOfB());
Console.ReadKey();
}
}
}
3.类的继承 Child:Parent
(1)C#只支持单继承,但可以通过接口来实现多继承
(2)派生类继承了基类的public、protected、internal成员变量和成员方法。
(3)若不指明,创建子类对象调用子类的构造函数时,会默认首先调用父类的无参构造函数
namespace netBasic_learning
{
//3.类的继承 Child:Parent
// (1)C#只支持单继承,但可以通过接口来实现多继承
// (2)派生类继承了基类的public、protected、internal成员变量和成员方法。
// (3)若不指明,创建子类对象调用子类的构造函数时,会默认首先调用父类的无参构造函数
class Shape
{
protected double length;
protected double width;
public Shape(double len,double wid)
{
length = len;
width = wid;
}
public double GetArea()
{
return length * width;
}
public void Display()
{
Console.WriteLine("长度: {0}", length);
Console.WriteLine("宽度: {0}", width);
Console.WriteLine("面积: {0}", GetArea());
}
}
class Cube:Shape
{
private double height;
public Cube(double len,double wid,double hei): base(len, wid)//base(x,y)初始化父类参数,先于子类执行
{
height = hei;
}
public double GetVolume()
{
return height * GetArea();
}
public void Display()
{
base.Display();//通过base来指代当前对象的父类
Console.WriteLine("体积: {0}", GetVolume());
}
public static void Main(string[] args)
{
Cube cube = new Cube(2, 3, 4);
cube.Display();//调用子类的覆盖方法
Console.ReadKey();
}
}
}
1.多态:多态是根据不同的场景同一个行为具有多个不同表现形式或形态的能力。
(1)静态多态:函数的响应是在编译时发生的。
- 函数重载:对相同的函数名有多个定义。可以是参数列表中的参数类型不同,也可以是参数个数不同。不能重载只有返回类型不同的函数声明。
- 运算符重载:可以重定义或重载 C# 中内置的运算符。通过关键字 operator 后跟运算符的符号来定义的,同时包含 public 和 static 修饰符。
namespace netBasic_learning
{
//1.多态:多态是根据不同的场景同一个行为具有多个不同表现形式或形态的能力。
// (1)静态多态:函数的响应是在编译时发生的。
// - 函数重载:对相同的函数名有多个定义。可以是参数列表中的参数类型不同,也可以是参数个数不同。不能重载只有返回类型不同的函数声明。
// - 运算符重载:可以重定义或重载 C# 中内置的运算符。通过关键字 operator 后跟运算符的符号来定义的,同时包含 public 和 static 修饰符。
class Vector
{
private int x;
private int y;
public Vector()
{
x = 0;
y = 0;
}
public Vector(int _x,int _y)
{
x = _x;
y = _y;
}
public int getX() { return x; }
public int getY() { return y;}
public void setX(int x) { this.x = x; }
public void setY(int y) { this.y = y; }
public void Display()
{
Console.WriteLine("Vector({0},{1})", x, y);
}
// 重载 + 运算符来把两个 Vector 对象相加(可以直接访问private)
public static Vector operator +(Vector a, Vector b)
{
Vector C = new Vector();
C.x = a.x + b.x;
C.y = a.y + b.y;
return C;
}
// 重载 - 运算符来把两个 Vector 对象相减(可以直接访问private)
public static Vector operator -(Vector a, Vector b)
{
Vector C = new Vector();
C.x = a.x - b.x;
C.y = a.y - b.y;
return C;
}
// 重载 * 运算符来把两个 Vector 对象相乘(可以直接访问private)
public static int operator *(Vector a, Vector b)
{
return a.x * b.x + a.y * b.y;
}
public static void Main(string[] args)
{
Vector a = new Vector(2, 3);
Vector b = new Vector(3, 4);
//+法
Vector c = a + b;
c.Display();
//-法
c = a - b;
c.Display();
//*法
int res = a * b;
Console.WriteLine(res);
Console.ReadKey();
}
}
}
(2)动态多态:函数的响应是在运行时发生的。
- 虚方法(virtual ):定义子类可以重写覆盖父类的方法,对虚方法的调用是在运行时发生的。子类需要使用override声明
+ 父类定义虚方法,子类可以实现重写父类虚方法,也可以不实现重写。如果重写了,那么创建子类对象后,不管是父类指针还是子类,调用虚方法都会执行子类的覆盖。
+ 父类定义虚方法,必须要有父类的实现,在父类中是一个普通函数。
- 抽象(abstract ):抽象abstract关键字可以作用在方法上,也可以作用在类上。子类需要使用override声明
+ 父类抽象方法没有实现,只有声明。子类必须实现父类的抽象方法
+ 类内任何一个方法是抽象的,则该类必须被声明为抽象类。即抽象方法只能在抽象类中定义
+ 抽象类不能被实例化,但可以指向子类实例。子类若不实现抽象方法则也会变成抽象类。
- 总结:简单说,抽象方法是需要子类去实现的。虚方法是已经实现了的,可以被子类覆盖,也可以不覆盖,取决于需求。抽象方法和虚方法都可以供派生类重写。
namespace netBasic_learning
{
//动态多态:函数的响应是在运行时发生的。
// - 虚方法(virtual ):定义子类可以重写覆盖父类的方法,对虚方法的调用是在运行时发生的。子类需要使用override声明
// + 父类定义虚方法,子类可以实现重写父类虚方法,也可以不实现重写。如果重写了,那么创建子类对象后,不管是父类指针还是子类,调用虚方法都会执行子类的覆盖。
// + 父类定义虚方法,必须要有父类的实现,在父类中是一个普通函数。
// - 抽象(abstract ):抽象abstract关键字可以作用在方法上,也可以作用在类上。子类需要使用override声明
// + 父类抽象方法没有实现,只有声明。子类必须实现父类的抽象方法
// + 类内任何一个方法是抽象的,则该类必须被声明为抽象类。即抽象方法只能在抽象类中定义
// + 抽象类不能被实例化,但可以指向子类实例。子类若不实现抽象方法则也会变成抽象类。
// - 总结:简单说,抽象方法是需要子类去实现的。虚方法是已经实现了的,可以被子类覆盖,也可以不覆盖,取决于需求。抽象方法和虚方法都可以供派生类重写。
abstract class Animal
{
//抽象类:包含至少一个抽象方法,但是不仅仅包含抽象方法
protected string name;
public Animal(string _name)
{
name = _name;
}
//抽象方法:叫
abstract public void shout();
//虚方法
virtual public void eat()
{
Console.WriteLine("{0} is eating",name);
}
}
class Dog : Animal
{
public Dog(string name):base(name)
{
}
//实现抽象类
public override void shout()
{
Console.WriteLine("A Dog {0} is wangwang",name);
}
//覆盖重写虚函数
public override void eat()
{
base.eat();
Console.WriteLine("A Dog {0} is eat bone", name);
}
}
class Cat : Animal
{
public Cat(string name) : base(name)
{
}
//实现抽象类
public override void shout()
{
Console.WriteLine("A Cat {0} is miaomiao", name);
}
//覆盖重写虚函数
public override void eat()
{
base.eat();
Console.WriteLine("A Cat {0} is eat fish", name);
}
public static void Main(string[] args)
{
Animal[] animals = new Animal[2] { new Dog("tom"), new Cat("marry") };
foreach(Animal animal in animals)
{
animal.shout();
animal.eat();
}
Console.ReadKey();
}
}
}
2.接口(interface):接口类似于抽象类,但接口内所有方法都是抽象的
(1)接口不能实例化,继承接口必须实现所有抽象方法(不用声明override),接口可以指向子类(多态)
(2)接口默认声明为public
(3)接口可以多继承,解决 C# 里面类可以同时继承多个基类的问题。
(4)接口可以继承接口
namespace netBasic_learning
{
//2.接口(interface):接口类似于抽象类,但接口内所有方法都是抽象的
// (1)接口不能实例化,继承接口必须实现所有抽象方法(不用声明override),接口可以指向子类(多态)
// (2)接口默认声明为public
// (3)接口可以多继承,解决 C# 里面类可以同时继承多个基类的问题。
// (4)接口可以继承接口
interface Parent
{
void disPlay();
}
class Child : Parent
{
public void disPlay()
{
Console.WriteLine("child is display!");
}
}
}