数据类型

数据类型 值类型 引用类型 s b y t e b y t e s h o r t u s h o r t o b j e c t 预 定 义 类 型 i n t u i n t l o n g u l o n g s t r i n g f l o a t d o u b l e d e c i m a l b o o l c h a r d y n a m i c 用 户 定 义 s t r u c t c l a s s i n t e r f a c e 类 型 e n u m d e l e g a t e a r r a y \begin{array}{|c|c|c|} \hline \text{数据类型} & \text{值类型} & \text{引用类型} \\ \hline & sbyte \space byte \space short \space ushort & object \\ \newline 预定义类型 & int \space uint \space long \space ulong & string \\ \newline & float \space double \space decimal \space bool \space char & dynamic \\ \hline 用户定义 & struct & class \space \space interface \\ \newline 类型 & enum & delegate \space \space array\\ \hline \end{array} 数据类型预定义类型用户定义类型​值类型sbyte byte short ushortint uint long ulongfloat double decimal bool charstructenum​引用类型objectstringdynamicclass  interfacedelegate  array​​

值类型

符号 描述 BCL名(不使用) 后缀(用大写)
sbyte 8-bit signed System.SByte
byte 8-bit unsigned System.Byte
short 16-bit signed System.Int16
ushort 16-bit unsigned System.UInt16
int 32-bit signed System.Int32
uint 32-bit unsigned System.UInt32 U u
long 64-bit signed System.Int64 L l
ulong 64-bit unsigned System.UInt64 UL ul
float 32-bit 7位有效数字 System.Single F f
double 64-bit 15~16位有效数字 System.Double D d
decimal 128-bit 28~29位有效数字 能保持精度的特殊浮点类型 System.Decimal M m
bool 8-bit System.Boolean
char 16-bit Unicode编码 System.Char

事实上,简单类型(以上类型)在C#中实现为struct

数字写法
  • 下划线间隔 9_455_533U
  • 指数计数法 60.0615E23
  • 其他进制 0x123 0b1101 (没有八进制)
浮点类型

floatdouble0f/0NaN (Not a Number), 1f/0Infinity

避免在比较中使用float和double这两种二进制浮点类型( double == float 等),要么使用十进制浮点类型 decimal ,要么判断两数之差在容差范围内。

布尔类型

在C#语言中,预定义类型不能显示或隐式转换为 bool
if for while 语句中必须使用 bool

int i = 12;
if(i) ...; // Error

重载了 true/falseoperator bool 操作符的类可以在 if for while 语句中使用,详见***良好构建***

引用类型

string 字符串

C#的字符串使用Unicode字符

  • 构建

    string s = "123";
    s = new string('c', 4); // "cccc"
    
  • 比较

    Write(string.Compare("abc", "ABC"));
    Write(string.Compare("abc", "ABC", true)); // 忽略大小写
    // string.Compare返回-1, 0, 1三种值
    bool a = "abc" == "Abc";
    a = "abc".Equals("ABC");
    

    一般来说,引用类型的 == 操作符比较的是引用(地址)是否相等,但 string 类型比较的时引用的值是否相等

  • 其他方法

    // 用法看函数名就知道了
    string s = "abcABC";// 因为string是不可变的,所以以下方法都是有返回值的,System.Text.StringBuilder
    s.Contains("abc");
    s.IndexOf("cAB");
    s.LastIndexOf("bcA");
    s.IndexOfAny(new char[]{'c', '#', '?'});s.Substring(2, 5);
    s.Insert(2, "<>?");
    s.Remove(2, 5);
    s.Replace("bc", "");s.TrimStart();
    s.TrimEnd();
    s.Trim();string.Join(",", new string[] {"abc", "123"});
    s.Split(new char[] {' ', ','});s.ToUpper();
    s.ToLower();
    
  • 插值字符串 $"12{arg}3abc"arg 为上文变量常量名

  • 原生字符串 @"\n\t465"" "

  • 结合 $@"\{arg}""\"$@

    Windows: CRLF “\r\n”
    Unix: LF “\n”
    使用System.Environment.NewLine换行

object类型
object ob = 12;
System.Console.Write(ob);
ob = "8465"; // 可存储不同类型
System.Console.Write(ob);int val = 45;
object obj = val; // boxing
val = (int)obj; // unboxing
tuple 元组
(string country, string capital, double GDP) = ("England", "London", 2829.11);
System.Console.WriteLine($"{capital} {country}: {GDP}");var (country, capital, GDP) = ("England", "London", 2829.11);
System.Console.WriteLine($"{capital} {country}: {GDP}");var countryInfo = (Country: "England", Capital: "London", GDP: 2829.11);
System.Console.WriteLine($"{countryInfo.Capital} {countryInfo.Country}: {countryInfo.GDP}");
System.Console.WriteLine($"{countryInfo.Item1} {countryInfo.Item2}: {countryInfo.Item3}");var countryInfo = ("England", "London", 2829.11);
System.Console.WriteLine($"{countryInfo.Item1} {countryInfo.Item2}: {countryInfo.Item3}");
数组
  • 定义

    string[] text; // one dimension
    int[,] cells; // two dimensions
    // 只声明是无法使用的string langs = {"C", "Python", "Csharp", "Java"}; // 声明时同时赋值
    text = {"one", "second", "the"}; // error: 声明和赋值分开的话要用new
    text = new [] {"one", "second", "the"};
    cells = new int[3,4];
    int arr = new int[4] { 1, 2, 3 }; // error: []内数字因与{}内数量一样, 4 != len({1, 2, 3})System.Console.Write(cells[1, 2]);int[][] narr = {new int[]{1,2,3,4},new int[4], // 注意全初始化为default(int){1,2,3} // error: 必须由new创建
    } // 交错数组 或 数组的数组int[][] narr;
    narr = new int[2/*与后面new的个数相同相同*/][/*不填*/] { new int[] { 1, 2, 3, 4 }, new int[4] };System.Console.Write(narr[0][2]);
    
  • 改变大小

    int[] arr = new int[20];
    Array.Resize(ref arr, 45);
    
  • 方法

    // arr会被改变
    arr.Sort();
    arr.Sort(x => Math.Abs(x));
    Array.Reverse(arr);
    

    其他方法可以见集合和集合

初始值

每种类型都有对应的初始值,可以通过 default(type) 查看

int a = default(int);
int b = default; // both are ok

类型转换

  • 显式 long b = 12; int a = (int)b

  • 隐式 long b; int a = 12; b = a

  • System.Convert

    double d = System.Convert.ToDouble("123.2");
    bool b = true;
    string s = b.ToString(); // s == "True"
    
  • Parse和TryParse

    int a = int.Parse("12"); // 无法转换引发异常
    int.TryParse("12", out a); // 无法转换返回false,转换成功时将值存在a中
    int.TryParse("45", out _); // 舍弃
    
  • unchecked(慎重使用)

    unchecked {uint a = (int)-1;
    }
    
  • CLR技巧(慎重使用)

    uint[] arr = (uint[])(System.Array)new int[]{ -1, -2, -3 };
    

    不同的CLR不一定都能实现此技巧

  • 枚举类型转换

    枚举

其他类型

可空类型
int? i = null; // 可以标记值是否为null
i.HasValue; // 返回i是否为null,即 i != null
i.Value; // 若i不为空,返回i的值System.Console.WriteLine(i.HasValue ? i.Value : 0);
System.Console.WriteLine(i ?? 0);// 实际上是一种语法糖
Null<T> t = new Nullable<T>();
T? t = new T();
// 二者等价
隐式类型和匿名类型
var s = "ads".ToUpper();
// 类型由编译器推断,类似C++的auto关键词
// JavaScript的var和VB的Variant则类似于C#的object
System.Console.WriteLine(s);

Comparison: auto in C++ and var in C#

var i = 10;
var info = ("abc", 456, 3.14F); // 支持元组
auto i = 10;
auto foo() -> int { return 5; }
auto bar() -> decltype(printf) { } // 尾置返回template<typename T, typename U>
auto add(T t, U u) { return t + u; }

auto的用法更加广泛,而var只能用在变量声明时

auto是C/C++原有的关键字,但几乎只有编译器作者才会使用,使用auto而不使用var可做到:

  • 不新增关键字
    减少设定新关键字的工作,也能兼顾使用了var作变量名的旧代码,还能兼容C
  • 更贴切
    在多种无类型语言、解释型语言和动态语言中,var一般用作无类型变量声明

### 流程控制

基本流程控制语句
语法结构 特性
if (boolean-expression) {
operation
}
else {
operation
}
嵌套(连贯):
if() {}
else if() {}
else if() {}
else if() {}
else {}
while (boolean-expression) {
operation
}
改尾递归为迭代
称一次循环为一次迭代
do {
operation
}
while (boolean-expression)
至少执行一次
常用于提示用户输入
for (initializer; boolean-expressing; iterator) {
operation
}
init -> bool ->
body(out) -> iter -> bool (loop<<-)
foreach (type variable in collections) {
operation
}
type是collections中每一项的数据类型,可用var。
循环期间禁止修改变量(const)
switch(type-expression) {
case const-expression:
operation
jump-out
(more cases)
default:
operation
jump-out
}
case和default及后续语句称为switch小节
每个小节的结尾必须是break或return或goto(不能贯穿)
continue;
break;
goto identifier;
goto case const-expression;
goto default;
switch中可用goto case/default跳转到其他小节
出现过多这种情况,请重构以避免使用过多goto
特殊操作符
cond ? true-state : false-state // cond为true,等价于true-state,否则为false-state true-state和false-state类型相同expression1 ?? expression2 // 等同于 expression1 != null ? expression1 : expression2 但expressions1并不会计算两次
expression1 ?? expression2 ?? expression3args?.Attr // 等同于 args != null ? (typeof(args.Attr)?)args.Attr : null 但args并不会计算两次
args?.Attr ?? false

异常处理

try/catch/finally

void F(int val) {try {Foo();throw new ArgumentException("invalid value", nameof(val));// 此时Foo()会被执行Bar()不会Bar();}catch (Win32Exception e)when (e.NativeErrorCode == 42) /* when后可以加异常条件表达式 */ {// Handle Error}catch (ArgumentException e) {System.Console.WriteLine(e.Message);}catch (Exception e /*  Exception是所有异常的基类 */ ) {throw; //使用空throw可以保存Error的栈信息,将Error再次抛出throw e; //如果使用这种方法会使得Error的信息被改变,不推荐使用}catch () {} // Error: Exception是最宽泛的异常类了finally {// 无论是否发生异常都会到达的块,常用于释放资源}
}

如果用户输入非法参数,使用通常的流程处理进行处理和返回信息而非通过异常处理进行处理和返回信息

越宽泛的异常越放在后面, System.Exception 是最宽泛的异常所以应该放在最后,可以用 catch {} 代替

事实上, catch {}catch (object) {} ,但不能直接写成后者

规范
  • 只捕捉能处理的异常
  • 不隐藏不能处理的异常
  • 少用 System.Exceptioncatch {} 捕捉异常
  • 不在调用栈较低的位置报告或记录异常,允许异常在调用栈上向上传播
  • 使用 throw; 而不是 throw e;
  • 想好异常条件避免在 catch 中抛出异常
  • 避免在异常条件表达式中抛出异常
  • 避免以后可能变化的异常条件表达式
  • 重写抛出异常时要小心

方法

命名空间

namespace.class.function
几乎所有C#程序都要用System命名空间

using System; // 引入命名空间
using static System.Console; // 加static引入类和方法
using Csl = System.Console; // 使用别名
// 引入后即可不加前缀(除非名字冲突),但为清楚命名空间和类,本文使用全称

using 也可在命名空间中使用,但不应该这样使用

声明和定义方法

一般来说,C#不区分声明和定义,除非使用名为分部方法的高级功能(查看分布类部分)

class A{public static void Foo(){// 可被外部访问,静态,无返回值}private static int Bar(){// 不可被外部访问,静态,返回int值}public string Baz(int a){// 可被外部访问,非静态,返回string值}private (string Country, double GDP) Qux(){// 不可被外部访问,非静态,返回元组return ("London", 1.123);}private string Fun(string s1, string s2) => $"{s1} {s2}"; // 简化表达式主体方法
}
参数

引用参数

static void Main() {int x = 0;Foo(x); // x不变FooRef(ref x);FooOut(out x); // 可以使用 FooOut(out int y) 直接赋值yFooIn(in x);// ref, out, in传递的都是引用int[] arr = {1, 2, 3, 4};Foo(arr);// arr[3] == 12
}static void Foo(int x) { ++x; }
static void FooRef(ref int x) { ++x; }
static void FooOut(out int x) { x = 12; } // 必须赋值x否则报错
static void FooIN(in int x) { System.Console.WriteLine(x); } // x只读
static void FooArr(int[] x) { x[x.Length-1] = 12; } // 传递引用类型
static void F()
{int[] a = { 1, 2, 3 };int[] b = { 4, 5, 6 };Swap(ref a, ref b); // 交换数组
}
public static void Swap<T>(ref T a, ref T b)
{T t = a; a = b; b = t;
}

参数数组

static void Main(){Fun("one", "adsj", "532");string[] t = {"one", "adsj", "532"};Fun(t);Fun(); // empty is Ok
}static void Fun(params string[] strs){// params参数只能放在最后,若想保证最少参数数量可以写成(string, params string[])foreach (string s in strs) System.Console.WriteLine(s);
}

可选参数和具名参数

static void F(string name = "Andy", int seq = 1) => System.Console.Write($"{name}: {seq}");
static void A() => F();
static void B() => F(seq: 5, name: "Kid");
返回引用
// 所有的ref都不可缺少
public static ref int F(int[] arr){return ref arr[arr.Length-1];
}
static void A(){int[] arr = {1, 2, 3};ref int val = ref F(arr); // val即arr[2]int a = 12;ref int b = ref a;// ref局部变量不能修改,不能用字面值初始化,必须立即初始化
}
class A {ref string s; // error: 不允许声明ref字段string str;public ref string Str { // error: 不允许把自动属性声明为引用类型get{ return str; }set{ str = value; }}public ref string GetStr(){return ref str; // correct: 允许返回引用的属性}
}
重载

操作性多态的实现

void Foo(string s) {}
void Foo(string s, int a=0) {} // 错误:使用可选参数时无法与上式区分
void Foo() => Foo(string.Empty); // 将实现主体转移到Foo(string)中,另类的可选参数void Bar(int a) {}
int Bar(int a) {} // 错误:不能只靠返回值区分方法

方法的唯一性通过方法名、参数类型和参数数量来确定

迭代和递归

递归意味着方法调用自身,反之为迭代
可以用while改写尾递归
用stack改写头递归和中间递归

递归实现方法:

F(x) {if (reach the end)return;else {breakdown x into small onesF(smaller x); // use F(x) as if F(x) has been able to solve questions}
}

Main方法

命令行参数和返回值

$ .\Program -a.cfg -b.log # 调用可执行文件
class Program{static int Main(string[] args){foreach (string arg in args)System.Console.WriteLine(arg);/*-a.cfg-b.log*/return 1; // 非0值代表非正常退出(此处示例),交由操作系统或其他程序判断}
}
$ echo $? # False

规范

System.Console.WriteLine($"Hello, {0}!", System.Console.ReadLine());
// which is better?
string name = System.Console.ReadLine();
System.Console.WriteLine($"Hello, {0}!", name);

通常情况下,Readability胜于Short

用动词或动词短语按PascalCase作方法名

C#语法基础(本质论笔记其一)相关推荐

  1. Java语法基础学习笔记05-1-循环案例+嵌套for-重点

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.单层for循环案例代码 二.for循环嵌套 1.图形打印 1.1**矩形 1.2**直角三角形 1.3**倒直角三 ...

  2. 读书笔记(06) - 语法基础 - JavaScript高级程序设计

    写在开头 本篇是小红书笔记的第六篇,也许你会奇怪第六篇笔记才写语法基础,笔者是不是穿越了. 答案当然是没有,笔者在此分享自己的阅读心得,不少人翻书都是从头开始,结果永远就只在前几章. 对此,笔者换了随 ...

  3. 《C#本质论(第4版)》一1.2 C#语法基础

    本节书摘来异步社区<C#本质论(第4版)>一书中的第1章,第1.2节,作者: [美]Mark Michaelis , tEric Lippert译者: 周靖 责编: 杨海玲,更多章节内容可 ...

  4. Java基础笔记(入门,语法基础,流程控制,数组)

    Java语言入门 发展历程 三大技术体系 JavaSE 标准版 JavaEE 企业版 JavaME 嵌入式版 Java语言特点 简单性 健壮性 面向对象 分布式 多线程 动态性 可移植性(跨平台) J ...

  5. JavaSE笔记(语法基础篇)

    文章目录 语法基础篇 第1章 概述 1.1 计算机组成部分 1.2 人机交互方式 1.3 计算机语言 1.4 软件与软件开发 1.5 Java语言介绍 1.6 Java开发环境搭建 1.7 常见错误 ...

  6. guido正式发布python年份_Python 基础学习笔记.docx

    Python 基础学习笔记 基于<Python语言程序设计基础(第2版)> 第一部分 初识Python语言 第1章 程序设计基本方法 1.1 计算机的概念 计算机是根据指令操作数据的设备, ...

  7. Python基础入门笔记(二)

    前言 本文主要为 Python基础入门笔记(一)内容的补充. 一.迭代器和生成器 1.1 Python迭代器 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元 ...

  8. 11岁过python1级_11岁表弟写的Python零基础入门笔记!

    一.Python输入与输出输出:使用print()函数. print()函数的基本语法格式如下:print(输出内容). 输出内容可以是数字和字符串(字符串需要用引号括起来),也可以是包含运算符的表达 ...

  9. Python3 基础学习笔记 C08 【类】

    CSDN 课程推荐:<8小时Python零基础轻松入门>,讲师齐伟,苏州研途教育科技有限公司CTO,苏州大学应用统计专业硕士生指导委员会委员:已出版<跟老齐学Python:轻松入门& ...

  10. Python3 基础学习笔记 C07【函数】

    CSDN 课程推荐:<8小时Python零基础轻松入门>,讲师齐伟,苏州研途教育科技有限公司CTO,苏州大学应用统计专业硕士生指导委员会委员:已出版<跟老齐学Python:轻松入门& ...

最新文章

  1. java里class有什么用_安装JDK时的java和javac命令有什么用?
  2. 该文件 linux命令,Linux网络系统,如果执行行命令#chmod 746 file.txt,那么该文件的权限是?...
  3. JSP学习笔记(七):使用JavaBean
  4. R语言入门学习笔记 - 对R软件的认识
  5. 安装系统要求错误_【船机帮】康明斯船用柴油机燃油系统的安装要求
  6. 3DSlicer31:结构的实例分析IGSReader
  7. 接口本地正常服务器报500_运维该如何解决服务器底层维护难题?
  8. linux 改用户组密码,Linux用户和组的操作(八) 修改用户密码 passwd
  9. java什么是网络接口_java接口和类的区别是什么?它们都有哪些作用呢?
  10. 高性能网站建设的14个原则(转载)
  11. (转) java 复制文件,不使用输出流复制,高效率,文件通道的方式复制文件
  12. wps如何保存最终状态_如何使得打开word文件显示最终的修改状态
  13. python中二进制表示_Python中的二进制搜索:直观介绍
  14. FileZilla Server远程管理
  15. Android 四大组件学习之Server一
  16. 固高GTS运动控制卡,C#语言三轴点胶机样本程序源代码
  17. jike2021总结
  18. raster包—aggregate函数
  19. 阿里云建站套餐怎么样?具体建站流程
  20. Broccoli Tree Creator 使用说明 3_3、Girth Transform Node (周长变换节点)

热门文章

  1. android sdk库 离线安装,android sdk 离线安装
  2. 后渗透篇:COM Object hijacking 后门实现思路——劫持CAccPropServicesClass and MMDeviceEnumerator
  3. java mq_java实现MQ消息收发两种方式
  4. OSChina 娱乐弹弹弹——人怕出名猪怕壮,红薯出名会怎样?
  5. 数据库与缓存一致性解决方案
  6. Redis(六) 数据库和缓存的一致性问题
  7. socket阻塞和非阻塞
  8. 用WebStorm搭建vue项目
  9. 在vi和vim上查找字符串
  10. Linux网络实战(一)- DNS配置