最近打算把C#基础重新学一遍,所以发个C#的学习日记,接触C#有近半年了,发现C#在做界面上确实非常强大。以下文章为C#第一章,包括 值与引用,string类型匹配与转义,基本函数,带ref函数,带out函数,运算符,枚举,结构体。参考图书:《C#:开发技术大全》
一.值与引用
值类型存储的是值,而引用类型存储的是对值的引用,相当于C语言的指针将一个值赋值给另外一个变量时,将会新开辟一个内存空间给新变量用来存储值。而对于引用类型,不会新开辟存储空间,只会将地址赋给新的变量。值类型不能包含null,但是引用类型可以。引用类型为Object和String类型,char类型属于String类型内。Object类型是Object的别名,C#中可以将任何类型的值赋给Object类型的变量。
#region valueANDreference
/// <summary>
/// 值与引用
/// </summary>
public void valueANDreference()
{
// new 创建的对象初始值是0.不同类型的默认值不同,但是都有默认值
short shortnew = new short();
char charnew = new char();
byte bytenew = new byte();
short shortS; <span style="font-family: Arial, Helvetica, sans-serif;">//直接定义为未附值,要想使用需要赋值,此处是未赋值,不是NULL</span>
shortS = 1;
Console.WriteLine("short shortnew = new short():{0},
TYPE:{1}", shortnew, shortnew.GetType());
Console.WriteLine("char charnew = new char():{0},
TYPE:{1}", charnew, charnew.GetType()); //char类型默认初始值是null
Console.WriteLine("byte bytenew = new byte():{0},
TYPE:{1}", bytenew, bytenew.GetType());
Console.WriteLine("short shortS=1:{0},
TYPE:{1}, TYPECODE:{2}", shortS, shortS.GetType(), shortS.GetTypeCode());
Console.WriteLine();//空行,等同于ENTER
object objclass = new refClass(); //object 类型,创建类的实例
refClass refclass = (refClass)objclass; //若要将object 类型转化为类实例,需先强制转化
refClass newrefclass = new refClass();
refclass.refint = 1;
Console.WriteLine("类中成员值改变后输出:refint={0}", refclass.refint);
Console.WriteLine("类中成员值未改变后输出:newrefint={0}", newrefclass.refint);
Console.WriteLine();//空行,等同于ENTER
}
#endregion
#region refClass
/// <summary>
/// 用于引用的类
/// 关于类的使用后面再说
/// </summary>
class refClass
{
public int refint = 0; // 为什么此处一定要用public
}
#endregion
二.string 类型匹配与转义
string类型为引用类型(指针类型)
所以在以下程序中我们可以看出,对于值的比较,是TRUE
而对于a和b实例的比较,是FLASE,说明a和b引用的不是同一个string实例。(即a与b指向的不是同一个内存地址)
对于存在'\' 的字符串,如果不是表示转义,需要先对其处理,处理的方法有两种
1.再加一个\
2.在开头前加上@
<span style="white-space:pre"> </span>#region transferredMeaning
///<summary>
///string 类型
/// 值和引用的比较
/// 转义字符串
///</summary>
public void transferredMeaning()
{
string a = "hello";
string b = "h";
b = b + "ello";
string filepathA = "C\\ABC.text";//多加\转义
string filepathB = @"C\ABC.text"; //直接加@转义
Console.WriteLine("a=b直接匹配:{0}", a == b); //输出true
Console.WriteLine("(object)a=(object)b 引用匹配:{0}", (object)a == (object)b); //输出false
Console.WriteLine(); //空行,等同于ENTER
Console.WriteLine("string filepathA = \"C\\\\ABC.text\":{0}", filepathA);
Console.WriteLine("string filepathB = {0}:{1}", "@\"C\\ABC.text\"", filepathB);
}
#endregion
三.带参数方法
带一个基本参数的方法,就不用多说了
我们来说一说带ref引用与out输出的方法。
ref 引用,说白了,就是和C++中带指针参数的方法是相同的。掉用方法是,将变量的地址作为传递参数,
所以在方法里,对于参数的操作,即是对该变量内存空间内数字的直接操作,会改变变量的值。
out输出参数,与ref原理相同。区别是使用out修饰符,则在方法里要对参数进行赋值,而对于传递之前
有没有赋值则没有要求。
带引用参数或者基本参数的方法,在调用方法时,传递的参数一定要赋值。
<span style="white-space:pre"> </span>#region ClassTest
/// <summary>
/// ClassTest 类
/// 带一个参数
/// 带ref 参数
/// 带out 参数
/// </summary>
class ClassTest
{
/// <summary>
/// 带一个标准参数
/// </summary>
/// <param name="a">test</param>
public void test(string a)
{
a = "test";
string test = a; //static 为什么在方法里不能用
Console.WriteLine("标准参数的方法 test=a test={0}", test);
}
/// <summary>
/// 带一个ref 参数
/// </summary>
/// <param name="a">testref</param>
public void testref(ref string a)
{
a = "testref";
string testref = a;
Console.WriteLine("ref参数的方法 testref=a testref={0}", testref);
}
/// <summary>
/// 带一个out参数
/// </summary>
/// <param name="a">testout</param>
public void testout(out string a)
{
a = "testout";
string testout = a;
Console.WriteLine("out参数的方法 testout=a testout={0}", testout);
}
public void printf()
{
string teststring = "teststring";
test(teststring);
Console.WriteLine("teststring = {0}", teststring);
testref(ref teststring);
Console.WriteLine("teststring = {0}", teststring);
string teststringout;
testout(out teststringout);
Console.WriteLine("teststringout = {0}", teststringout);
}
}
#endregion
四.运算符
基本的运算符就不介绍了,介绍以下几种运算符。
赋值操作符的运算规则。
运算符的优先级
代码中几个位运算符。
1. | 或运算符。当且仅当两个运算符都位false时,结果才为flase。 下图为5|7的运算结果。
2. &与运算符。当且仅当两个操作数均为true时,结果才为true。下图为5&7的结果。
3.^异或运算符。当且仅当只有一个操作数为ture时,结果才为true。下图为5^7的结果。
4.~ 取补运算符。具体步骤如下。下图为5取补的结果。
5.左移操作符。a<<=b.等同于 a=a<<b.
6.右移操作符。同左移。
7. / 除法取整。当除数或者被除数为浮点型时,为除法计算。
8. % 取余。当除数为浮点型时,则计算小数点后相应位数的余数。
9.(?:)条件运算符。根据布尔型表达式的值返回两个值中的一个。如果条件是true,则计算第一个表达式并以计算结果为准。如果为false,则为第二个。
<span style="white-space:pre"> </span>#region Operator
/// <summary>
/// 运算符
/// </summary>
class Operator
{
class A
{
public const int a = 5;
public double b = 7.3;
public int c = 8;
}
class B : A
{
public int x = 6;
public double y = 2.734 + .5; //加小数可以直接加.X,不用加0
public int z = 7;
}
public void test()
{
Console.WriteLine("'/'运算符 取整 5/3 ={0}", 5 / 3);
Console.WriteLine("'/'运算符 除法 5/3.2={0}", 5 / 3.2);
Console.WriteLine("'%'运算符 取余 5%3 ={0}", 5 % 3);
Console.WriteLine("'%'运算符 取余 5%3.2={0}", 5 % 3.2);
A A = new A();
B B = new B();
B.x = B.c >= B.a ? B.a : B.c;
Console.WriteLine("关系运算符 B.x = B.c(8)>= B.a(5)? B.a : B.c B.x={0}", B.x);
Console.WriteLine("逻辑运算符 5|7 ={0}", 5 | 7);
Console.WriteLine("逻辑运算符 5&7={0}", 5 & 7);
Console.WriteLine("逻辑运算符 5^7={0}", 5 ^ 7);
Console.WriteLine("逻辑运算符 ~5 ={0}", ~5);
int a = 2, b = 3, c = 5, d = 1;
Console.WriteLine("左移位运算符 a=2,b=3 a<<=b,a={0}", a <<= b);
Console.WriteLine("右移位运算符 c=5,d=1 c>>=d,c={0}", c >>= d);
}
}
#endregion
五.枚举
枚举是值类型的一种特殊形式。它从System.enum继承而来。
如存在基础类型,基础类型必须是一个内置的正数类型。枚举成员是静态文本字段。
其中每一个字段都表示为常数。同一值可以分配多个字段。
若同一值分配多个字段,则必须将其中某个值标记为主要枚举值,以便进行反射和字符串转换。
对于枚举还有以下附加限制:
枚举不能定义自己的方法。
枚举不能实现接口。
没救不能定义属性和事件。
枚举分为传统型枚举和位域型枚举,区别见代码。
<span style="white-space:pre"> </span>#region enumTest
/// <summary>
/// enumTest
/// 枚举
/// </summary>
class enumTest
{
/// <summary>
/// 枚举
/// enum 枚举名称[:基础类型]
/// {
/// 枚举成员1 [=整型变量], //此处是逗号分开
/// 枚举成员2 [=整型变量|枚举成员1] //表示此处整型变量,枚举成员1的整型变量都是枚举成员2的枚举
/// }
///
/// 位域通常用于由可组合初选的元素组成的列表,而枚举常数通常用于由互斥元素组成的列表
/// 因此,位域设计为通过或运算组合来生成未命名的值,而枚举常数则不是。
/// </summary>
enum InfoValue : long //带长整型的枚举,传统型枚举。
{
A = 0,
B, //未对其进行赋值,从结果中可以看出,会自动对其赋值。
C, //从结果可以看出,当检索不到值所对应的枚举成员时,则不处理。
D,
}
[Flags] //位域型枚举标识符
enum fields : short
{
Black = 0, //从结果可以看出,当检索不到值所对应的枚举成员时,系统会根据
Red = 1, //已存在的枚举成员累加和等于检索值的成员作为新成员。
Green = 2,
Blue = 4
}; //加不加分号的区别
enum SomeRootVegetable
{
枸杞,
西红柿,
苹果
}
[Flags] //域标识
enum Seasons
{
无 = 0,
夏天 = 1,
秋天 = 2,
冬天 = 4,
春天 = 8,
所有季节 = 夏天 | 秋天 | 冬天 | 春天
};
public void test()
{
Console.WriteLine("\r\n传统型枚举:");
for (int i = 0; i < 8; i++)
{
Console.WriteLine("{0,3}-{1}", i, ((InfoValue)i).ToString());
}
Console.WriteLine("\r\n位域型枚举:");
for (int i = 0; i < 8; i++)
{
Console.WriteLine("{0,3}-{1}", i, ((fields)i).ToString());
}
Console.WriteLine("\r\n位域型枚举 季节:");
for (int i = 0; i < 16; i++)
{
Console.WriteLine("{0,3}-{1}", i, ((Seasons)i).ToString());
}
Hashtable vgtblAndsn = new Hashtable();
vgtblAndsn[SomeRootVegetable.枸杞] = Seasons.春天;
vgtblAndsn[SomeRootVegetable.苹果] = Seasons.所有季节;
vgtblAndsn.Add(SomeRootVegetable.西红柿, Seasons.秋天 | Seasons.冬天); //与下面的语句效果一样
// vgtblAndsn[SomeRootVegetable.西红柿] = Seasons.秋天|Seasons.冬天;
Seasons[] seasons = new Seasons[]{Seasons.春天,Seasons.秋天,
Seasons.夏天,Seasons.冬天};//Seasons[] seasons=new Seasons[4];
//数组的创建必须有大小或者设置初始值
Console.WriteLine("\r\n枚举举例:");
for (int i = 0; i < seasons.Length; i++)
{
Console.WriteLine("以下蔬菜在{0,2}季节收获", seasons[i].ToString());
foreach (DictionaryEntry e in vgtblAndsn) //哈希表的遍历需要用到DictionaryEntry
{
if (((Seasons)e.Value & seasons[i]) > 0) //与运算
{
Console.WriteLine(((SomeRootVegetable)e.Key).ToString());
}
/* if(e.Value.ToString()==seasons[i].ToString())
{
Console.WriteLine(e.Key.ToString());
}
*/
}
}
}
}
#endregion
六.结构
结构是值类型,该类型将多个不用类型的成员组成一种新的类型,与类相同的是,结构成员的默认可访问级别也是private,如果需要调用,必须将其声明为public.
结构可以包含构造函数,常量,字段,方法,属性,索引器,运算符,事件和嵌套类型等。
结构的特点:
结构是值类型,而类是引用类型。
与类不同,结构实例化可以不使用new运算符。
结构可以声明构造函数,但其必须在参数。
一个结构不能从另一个结构或类继承,而且不能作为其他结构或基类。
结构可以实现接口。
结构可用null值对结构成员进行赋值。
<span style="white-space:pre"> </span>#region struct
/// <summary>
/// 结构体
/// 结构是值类型,该类型将多个不用类型的成员组成一种新的类型,
/// 与类相同的是,结构成员的默认可访问级别也是private,如果需要调用,必须将其声明为public.
/// 结构可以包含构造函数,常量,字段,方法,属性,索引器,运算符,事件和嵌套类型等。
/// struct 结构名称
/// {
/// 结构成员
/// }
///
/// 结构的特点:
/// 结构是值类型,而类是引用类型。
/// 与类不同,结构实例化可以不使用new运算符。
/// 结构可以声明构造函数,但其必须在参数。
/// 一个结构不能从另一个结构或类继承,而且不能作为其他结构或基类。
/// 结构可以实现接口。
/// 结构可用null值对结构成员进行赋值。
/// </summary>
class structTest
{
struct employee
{
public string name;
public int age;
public string sex;
public string address;
public employee(string name, int age, string sex, string address) //构造函数必须带参数
{
this.name = name; //而且要对结构体成员进行赋值
this.age = age;
this.sex = sex;
this.address = address;
}
}
struct company
{
public string name;
public object employee; //设置obj成员存储员工信息
public string phone;
public company(string name, object employee, string phone)
{
this.name = name;
this.employee = employee;
this.phone = phone;
}
}
public void test()
{
employee emp = new employee("move", 18, "男", "江苏南京"); //可以用new实例化,生成对象
company com; //也可以直接实例化
com.name = "南信大";
com.phone = "12345678901";
com.employee = emp;
Console.WriteLine("公司:{0}\r\n电话:{1}\r\n员工姓名:{2}\r\n员工性别:{3}\r\n员工地址:{4}\r\n",
com.name, com.phone, ((employee)com.employee).name,
((employee)com.employee).sex, ((employee)com.employee).address);
}
}
#endregion