在C#中,数据分为变量和常量两大类。变量又可以分为命名变量和匿名变量,匿名变量可以不事先制定变量的数据类型,而由程序在后续代码或表达式中决定该变量的数据类型。
C#中,使用“数据类型 变量名称”的方式声明一个变量,在声明变量的同时还可以对变量进行初始化。
在使用变量时,编译器会检查程序是否使用了还未初始化的变量,如果程序使用了还未初始化的变量,会导致一个编译错误。除此之外,编译器还未检查变量的值是否符合变量数据类型的要求。
在C#中,小数默认会被编译器理解为double类型,double类型只可以强转为float,不会转换成其他类型。所以,C#中定义了一些后缀,标识其他数据类型的整数或者小数,以避免初始化值时没有必要的数据类型转换,常见的后缀如下:
因为C#是强类型的语言,所以每个变量都需要明确地声明数据类型。公共语言运行时将使用指定的数据类型保存到内存中。
除了使用范型,使用强类型的数据是一项相当繁琐的工作,为了解决这个问题,C#在最新的版本中提供了”var“关键字,从而使C#程序能够使用匿名变量。C#程序中的匿名变量又可以称为隐式变量,匿名变量并非没有变量名,而是变量数据类型不确定。
使用匿名变量时需要谨慎使用,如果用的不好的话,可能会降低代码的可靠性和稳定性。
在C#中,匿名变量基于范型实现。也就是说,但程序中使用匿名变量时,公共语言运行时为变量在内存中预留一个位置,在这个位置上保留特殊的占位符。在后续程序执行时,会根据赋值的内容判断变量的数据类型。
using System;
using System.Collections.Generic;
namespace AnonymousVariableDemo
{
class Program
{
static void Main(string[] args)
{
var TestList = new List<int>(); // 定义并初始化匿名变量
/*
注意:
* 匿名变量必须在声明的同时初始化
* 在一个类中不能使用匿名变量,即使声明变量的同时对变量进行初始化,只能在本地变量的声明中使用“var”关键字定义匿名变量
*/
TestList.Add(11);
TestList.Add(12);
TestList.Add(13);
foreach(var i in TestList)
{
Console.WriteLine(i);
}
// 11、12、13
}
}
}
在C#中,使用const关键字声明一个常量。因为在程序中不能修改常量的值,所以声明常量的同时必须同时初始化该常量。
C#中,不支持变量转换为常量,也不支持常量指针,并且只能声明实例常量和局部常量。
using System;
namespace ConsDemo
{
class Program
{
const string CopyRight = "Copyright(c) by Wells";
static void Main(string[] args)
{
Console.WriteLine(CopyRight + " in {0}", DateTime.Now.Year.ToString());
}
}
}
分类:
变量的个数:一元运算符、二元运算符、三元运算符
类型:算数运算符、字符串运算符、赋值运算符、逻辑运算符、位运算符、其他运算符
加、减、乘、除、取余、自增、自减
类型运算符用于在程序中获取变量的数据类型信息,或者用于引用类型数据的转换。类型运算符的sizeof和typeof具有较高级别的优先级。
C#中的类型运算符如下:
运算符 | 运算方式 | 示例 |
---|---|---|
sizeof | 在unsafe代码段中获取数据类型占用的内存空间 | sizeof(a) |
is | 判断变量是否是指定的数据类型 | a is object |
typeof | 获取变量的数据类型 | typeof(a) |
as | 引用类型或可空类型的显式数据转换 | a as b |
注意:
using System;
namespace TypeOperator
{
class ClassA
{
public string SomeInfo
{
get;
set;
}
}
///
/// 定义B类派生自A类
///
class ClassB : ClassA
{
public string MyInfo
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
ClassB Instance = new ClassB();
Instance.SomeInfo = "Test Info";
Console.WriteLine("A类全名:{0}", typeof(ClassA).FullName); // TypeOperator.ClassA
unsafe
{
Console.WriteLine("int类型占用的字节:{0}", sizeof(int)); // 4
}
Console.WriteLine("Instance是否A类:{0}", Instance is ClassA); // true
Console.WriteLine("A类属性:{0}", (Instance as ClassA).SomeInfo); // Test Info
}
}
}
二进制的运算,包括按位与(&)、按位或(|)、按位非(!)、按位异或(^)和移位运算(左移<<、右移>>)
在C#中,位运算符仅能用于整型类型的数据,不同类型的整型数据类型,因为最高位溢出的位置不同,所以位运算的结果也会不同
using System;
namespace BitOperator
{
class Program
{
static void Main(string[] args)
{
int iValue = 255;
// (00000000 00000000 00000000 11111111)2
byte iByte = (byte)(iValue << 2);
// (iValue << 2) -> (00000000 00000000 00000011 11111100)2
// (byte)(iValue << 2) -> (11111100)2 = (252)10
int iInt = iValue << 2;
// iValue << 2 -> (00000000 00000000 00000011 11111100)2 = (1020)10
Console.WriteLine(iByte); // 252
Console.WriteLine(iInt); // 1020
}
}
}
在C#中,定义了三个逻辑运算符,分别是逻辑与(&&)、逻辑或(||)、逻辑非(!)
在C#中,有以下赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、>>=、<<=
赋值运算符的计算顺序从右向左
在C#中,有以下比较运算符:==、>、<、>=、<=、!=
在C#中,其他运算符大部分从C语言和Visual C++语言继承而来,其中指针类运算符只能用于unsafe代码段,C#编译器跳过unsafe代码段的安全检查,所以,在使用这些运算符时要特别注意代码的安全性。
"??"空接合运算符时C#语言新增的运算符,用于可空数据类型的运算。当某个变量的数据类型不是可空数据类型时,可以通过Nullable的构造函数将该变量转换为可空类型,这样转换可以简写成"基本数据类型?"的形式。
比如bool类型的值只能是true或者false,不可为空,可以通过bool?a=null的形式,声明可空布尔数据类型的变量,并为变量赋“null”。
运算符 | 运算方式 | 示例 |
---|---|---|
?: | 三元条件运算符 | a > 0 ? b : b+1 |
[] | 索引运算符 | a[0] |
. | 成员运算符 | a.b |
:: | 命名空间别名运算符 | a::b |
?? | 空接合运算符 | A??b |
* | 指针运算符 | *a |
& | 地址运算符 | &a |
-> | 间接寻址运算符 | a -> b |
using System;
using MyCollections = System.Collections;
namespace OtherOperator
{
class Program
{
static void Main(string[] args)
{
// 使用命名空间别名限制符查找标识符
MyCollections::ArrayList arr = new MyCollections::ArrayList();
arr.Add(0);
// 使用三元运算符为数组的第一个元素赋值
arr[0] = arr.Count < 0 ? 0 : AddValue((int)arr[0], 2);
// 在数组中添加一个为null的元素
arr.Add(null);
// 使用空接合运算符为第二个元素赋值
arr[1] = arr[1] ?? 5;
Console.WriteLine("数组元素依次为: {0}, {1}", arr[0], arr[1]); // 2, 5
unsafe
{
char theChar = 'Z';
// 声明指向字符变量地址的指针
char* pInt = (char*)&theChar;
System.Console.WriteLine("字符的地址是{0:X2}", (int)&theChar);
System.Console.WriteLine("字符指针的值是= {0}", *pInt);
}
}
static int AddValue(int i, int step)
{
return i + step;
}
/*
注意:
* ArrayList的元素类型为object数据类型,是一种可空类型,"??"运算符只能用于可空数据类型的运算
* 指针运算符只能用于unsafe代码段,并在编译时允许不安全代码
*/
}
}
C#中,优先级分为15个级别,表格如下:
运算符 | 优先级 | 备注 |
---|---|---|
a.b f(a) a[b] a++ a new typeof | 15 | 优先级高于变量之前使用 |
+ - ! ~ ++a a (T)a | 14 | 这里的+ -表示数值类型的符号,表示正数和负数 |
* / % | 13 | |
+ - | 12 | 这里的+ -表示加法、减法 |
<< >> | 11 | |
< > <= => is as | 10 | |
== != | 9 | |
& | 8 | |
^ | 7 | |
| | 6 | |
&& | 5 | |
|| | 4 | |
?? | 3 | |
?: | 2 | |
= *= /= %= += -= <<= >>= &= ^= |= | 1 | 赋值运算符的优先级最低 |
注意:在实际的编程中,可以使用()来保证运算次序
using System;
using System.Ling;
namespace CustomException
{
///
/// 自定义异常
///
class SameNumberException : Exception
{
///
/// 构造函数,继承Exception的构造函数,参数message表示异常信息
///
///
public SameNumberException(string message) : base(message)
{
}
}
class Program
{
static void Main(string[] args)
{
string[] Number = { "006", "007", "008", "007" };
try
{
CheckUserNumber(Number);
}
catch(Exception error)
{
Console.WriteLine(error.Message);
}
}
static void CheckUserNumber(string[] NumberData)
{
string[] distinct = NumberData.Distinct().ToArray();
// 返回数组的非重复编号
if(distinct.Length != NumberData.Length)
{
throw new SameNumberException("用户设置重复");
}
}
}
}
string strTmp = "abcdefg某某某";
int i = System.Text.Encoding.Default.GetBytes(strTmp).Length;
int j = strTmp.Length;
// i = 13 j = 10