C#入门经典_注释笔记

checked关键字:

//检查赋值是否数据溢出
//或者配置,项目-属性-生成-高级,检查上溢下溢

checked//unchecked 不检查
{
    destination = (int)source;
}

委托:

2种写法:

1,Calcul cal=new Calcul(Add);
2, Calcul cal=Add;

1,Calcul cal;   cal=new Calcul(Add);
2,Calcul cal;   cal=Add;

ps:情况2自动初始化一个委托

二维数组:

int[,] ints = new int[10,4];
ints[2, 2] = 1;

ref out关键字

ref out 等也可以改变函数的签名(命名+参数),从而实现重载

断点:

可以设置中断条件和击中次数。
如,a>=100,次数=100

析构函数:

class MyClass{
     ~MyClass(){
    }
}

~ 析构函数,垃圾回收器回收时自动调用
还将隐式调用基类的析构函数

隐藏基类方法,在子类中定义时加

new public void Do(){
    ...
}

类型比较:

myObj.GetType()==typeof(MyObjClass)

对对象类型的比较

myObj is objBase
myObj是objBase的子类,实现类,同类都为true

重载运算符: 例如:+

需要再进行+运算的类内部定义
ps:1,不能重载+=,-=。但如果重载它们对应的简单运算符,如+,则+=仍能像预期那样执行。
2,不能重载=,因为它有基本用途
3,不能重载&&和||,但同1理,重载&和|就够了
4,<和>,<=和>=必须成对重载

class Person
{
    public int Age { get; set; }
    public decimal Price { get; set; }
    public string Name { get; set; }

    public static Person operator +(Person p1, Person p2)
    {
        return new Person { Age = p1.Age + p2.Age };
    }

    public static bool operator >(Person left, Person right)
    {
        return left.Age > right.Age;
    }

    public static bool operator <(Person left, Person right)
    {
        return left.Price < right.Price;
    }
}

IComparable接口:

定义在要比较的对象的类中实现,类要实现IComparable接口

public int CompareTo(object obj)
{
    var person = obj as Person;
    if (person == null) throw new ArgumentException("参数错误");
    return Age - person.Age;
}

重写隐式(implicit),显式(explicit)转换:

class Person1
{
    public int Age { get; set; }

    public static implicit operator Person2(Person1 p1)
    {
        Person2 p = new Person2 { Age = p1.Age };
        return p;
    }
}

class Person2
{
    public double Age { get; set; }

    public static explicit operator Person1(Person2 p2)
    {
        Person1 p1 = new Person1();
        checked { p1.Age = (int)p2.Age; }
        return p1;
    }
}

ps:
同样可作用于泛型集合

父子类相互转换:

1会报错,2不会报错。
不能把父类实例转换成子类实例,只能把父类变量类型转换成子类变量类型

1
Person p = new Person();
Man m = (Man)p;
2
Person p1 = new Man();
Man m1 = (Man) p1;

如果强转换成as 则都不会报错,1为null,2不为null

??运算符:

int? val1 = null;
int result = val1*5 ?? 10;
int? result2=val1*5 ?? 10;

??等式的结果可以是int或int?,等式会自动进行转换

default关键字:

如果T是引用类型,则输出null
如果T是值类型,则输出默认值
e.g. int -> 0

Class MyClass<T>{
    public MyClass(){
        Console.WriteLine(default(T));
    }
}

约束类型

class MyClass<T1, T2> : MyClassBase 
     where T1 : class,new () where T2 : T1
{   }

ps:
1,约束类型:struct值类型,class引用类型,base-class任意基类,interface接口,new()有一个公共无参构造函数
2,多个约束之间用,分隔
3,new()作约束必须是指定的最后一个
4,约束必须出现在继承说明符的后面

协变和抗变:

应用于泛型接口和委托,继承关系默认支持协变
1,协变

List<string> liststr = new List<string>();
List<object> listobj = new List<object>();
listobj.AddRange(liststr); //参数为IEnumerable<object>

定义:

public class List<T> : IEnumerable<T>...
public interface IEnumerable<out T> : IEnumerable

ps:1,使用关键字out,则类型参数T只能作为方法的返回值
2,泛型类型参数可以从一个派生类隐式转化为基类,让一个带有协变参数的泛型接口(或委托)可以接收类型更加精细化,具体化的泛型接口(或委托)作为参数,可以看成OO中多态的一个延伸。

2,抗变(逆变)

class MyComparer : IComparer<object>
{
    public int Compare(object x, object y)
    {
        throw new NotImplementedException();
    }
}

IComparer<object> comobj = new MyComparer();
liststr.Sort(comobj); //参数为IComparer<string>

定义:

public interface IComparer<in T>

ps:1,使用关键字in,则类型参数T只能作为方法的参数
2,泛型类型参数可以从一个基类隐式转化为派生类,让一个带有协变参数的泛型接口(或委托)可以接收粒度更粗的泛型接口或委托作为参数,这个过程实际上是参数类型更加精细化的过程。

总结:协变让一个粗粒度接口(或委托)可以接收一个更加具体的接口(或委托)作为参数(或返回值);逆变让一个接口(或委托)的参数类型(或返回值)类型更加具体化,也就是参数类型更强,更明确。

引发事件时,会依次调用程序列表中每个处理程序,只要它们满足指定的条件即可。

委托的应用:

delegate int OperationDelegate(int left,int right);
void Function(OperationDelegate del)
{
    int left,right;
    //...
    del(left,right);
}
void int OperationEx(int left,int right)
{ return left+right; }

//Main
1,用方法创建委托

void Function(new OperationDelegate(OperationEx));

2,直接传递方法(默认创建委托)

void Function(OperationEx);

3,匿名方法

void Function(delegate(int left,int right){  return left+right; });

4,Lambda表达式

void Function((left,right) => left+right);  
//参数类型不用指定,会通过上下文推断出类型
Function((left,right) => (left-right)*right);

//Lambda表达式本质还是委托
//用Func来简化一个委托的定义。代替delegate xx….

Lambda表达式的解释:

可以用两种方式解释Lambda表达式,
第一,Lambda表达式是一个委托,可以把它表示为
如下泛型类型:
Action - lambda表达式不带参,返回void,
Action<> - lambda表达式最多8个参数,返回void,
Func<> - lambda表达式最多8个参数,返回不是void
//e.g.
Func lamb,前面的是参数,最后的bool是返回值

第二,可以把Lambda表达式解释为表达式树。
并不能直接执行。LINQ架构的泛型类 Expression<>,可用于封装Lambda表达式,
把它转换为相应的SQL脚本,以便在数据库中直接执行

工作目录:

//设置当前工作目录,并不是转移文件!
Directory.SetCurrentDirectory(Directory.GetCurrentDirectory()+"\\demo");
//当前工作目录字符串
Directory.GetCurrentDirectory();

FileStream:

FileInfo file = new FileInfo("test.txt");
//创建一个只读的流
FileStream stream = file.OpenRead();
//创建一个只写的流
FileStream stream1 = File.OpenWrite("test.txt");
//将文件指针移动到文件的第8个字节,起始位置为第1个字节
stream.Seek(8, SeekOrigin.Begin);
//将指针从当前位置向前移动2个字节,则指向8+2=10个字节
stream.Seek(2, SeekOrigin.Begin);
//查找文件中倒数第5个字节
stream.Seek(-5, SeekOrigin.End);
//FileStream 操作字节或字节数组的流
//Stream(StreamReader或StreamWriter)操作的是字符

FileStream读取数据:

//读取本身cs文件 
byte[] byData = new byte[200];
char[] charData = new char[200];
try
{
    FileStream stream = new FileStream("../../Program.cs", FileMode.Open);
    stream.Seek(110, SeekOrigin.Begin);
    stream.Read(byData, 2, 190);
}
catch (Exception e)
{
    Console.WriteLine("AN IO Exception throw!");
    Console.WriteLine(e.ToString());
    Console.ReadKey();
    throw;
}
Decoder d = Encoding.UTF8.GetDecoder();
d.GetChars(byData, 0, byData.Length, charData, 0);
Console.WriteLine(charData);

FileStream写入:

byte[] byData;
char[] charData;
try
{
    FileStream file = new FileStream("test1.txt", FileMode.Create);
    charData = "This is a charData array!".ToCharArray();
    byData = new byte[charData.Length];
    Encoder encoder = Encoding.UTF8.GetEncoder();
    encoder.GetBytes(charData, 0, charData.Length, byData, 0, true);
    file.Seek(0, SeekOrigin.Begin);
    file.Write(byData, 0, byData.Length);
}
catch (Exception)
{
    //...
    throw;
}

StreamReader/Writer的权限:

StreamReader/Writer 总是拥有对文件的读写权限,为了使用高级参数如,FileMode,FileAccess,可以在FileStream构造函数指定这些参数,然后通过FileStream创建StreamReader/Writer

读取数据的选择:

1,小文件,StreamReader.ReadToEnd();
2,大型文件,StreamReader.ReadLine(); 循环判断是否为空 或者

foreach (var item in File.ReadLines("test.txt",Encoding.Default))
{
    Console.WriteLine(item);
}
File.ReadLines 一次读取一行,迭代读取。返回IEnumerable<string>
File.ReadAllLines  打开一个文件,读取文件的所有行,然后关闭文件。返回string[]

压缩和解压缩类 输入读取类:

System.IO.Compression;

static void SaveCompressedFile(string fileName, string data)
{
    FileStream file = new FileStream(fileName, FileMode.Create, FileAccess.Write);
    GZipStream zip = new GZipStream(file, CompressionMode.Compress);
    StreamWriter sw = new StreamWriter(zip,Encoding.Default);
    sw.Write(data);
    sw.Close();
}
static string LoadCompressedFile(string fileName)
{
    FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read);
    GZipStream zip = new GZipStream(file, CompressionMode.Decompress);
    StreamReader sr = new StreamReader(zip, Encoding.Default);
    string data = sr.ReadToEnd();
    sr.Close();
    return data;
}

C#6.0 新特性

1,字符串插值(String Interpolation)

之前:
var Name = "Jack";
var results = "Hello" + Name; 或者  var results = string.Format("Hello {0}", Name);
Now:
var results = $"Hello {Name}";

之前:
Person p = new Person {FirstName = "Jack", LastName = "Wang", Age = 100};
var results = string.Format("First Name: {0} LastName: {1} Age: { 2} ", p.FirstName, p.LastName, p.Age);
Now:
var results = $"First Name:{p.FirstName} LastName:{p.LastName} Age:{p.Age}";

PS:还可以插入代码 - 相当于小脚本或Razor 的@{ },不过只能作用于string

Console.WriteLine($"Jack is saying { new Tools().SayHello() }");

2,空操作符 ( ?. )

之前:
if (user != null && user.Project != null && user.Project.Tasks != null && user.Project.Tasks.Count > 0)
{
    Console.WriteLine(user.Project.Tasks.First().Name);
}
Now:
Console.WriteLine(user?.Project?.Tasks?.First()?.Name);

还可用于数组索引器

User[] users = null;
Console.WriteLine(users?[1].Name); // 正常
Console.WriteLine(users[1]?.Name); // 报错

PS:以下代码并不会报错,也不会有输出。减少了空异常,但是我们却需要小心使用,因为有的时候我们确实是需要抛出空异常。那么使用这个特性反而隐藏了Bug

User user = null;
user?.SayHello();

C#6.0 新特性 2:

3, NameOf

Console.WriteLine(nameof(User.Name)); //  output: Name
Console.WriteLine(nameof(System.Linq)); // output: Linq
Console.WriteLine(nameof(List<User>)); // output: List

PS:NameOf只会返回Member的字符串,如果前面有对象或者命名空间,NameOf只会返回 . 的最后一部分, 另外NameOf有很多情况是不支持的,比如方法,关键字,对象的实例以及字符串和表达式

4,表达式方法体
一句话的方法体可以直接写成箭头函数,而不再需要大括号

private static string SayHello() => "Hello World";
private static string JackSayHello() => $"Jack {SayHello()}";
Console.WriteLine(SayHello());
Console.WriteLine(JackSayHello());

序列化对象:

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
class Product
{
    public long Id;

    public string Name;

    public double Price;

    [NonSerialized]
    string Notes;
    public Product(long id, string name, double price, string notes)
    {
        Id = id;
        Name = name;
        Price = price;
        Notes = notes;
    }
    public override string ToString()
    {
        return $"{Id}:{Name} (${Price:F2}) {Notes}";
    }
}

//Main中
List<Product> list = new List<Product>()
{
    new Product(1,"Pung",1000.0,"Good stuff."),
    new Product(2,"Soup",25.0,"Tasty."),
    new Product(4,"Hat Sauce",12.0,"One for the kids.")
};

Console.WriteLine("Products to save:");
list.ForEach(p => Console.WriteLine(p.ToString()));

IFormatter serializer = new BinaryFormatter();
FileStream file = new FileStream("Products.bin", FileMode.Create, FileAccess.Write);
serializer.Serialize(file, list);
file.Close();

FileStream fileLoad = new FileStream("Products.bin", FileMode.Open, FileAccess.Read);
List<Product> list2 = serializer.Deserialize(fileLoad) as List<Product>;
fileLoad.Close();

监控文件:

private FileSystemWatcher watcher;

public Form1()
{
    watcher = new FileSystemWatcher();
    watcher.Deleted += new FileSystemEventHandler(OnDelete);
    watcher.Renamed += new RenamedEventHandler(OnRenamed);
    InitializeComponent();
}

public void OnRenamed(object source, RenamedEventArgs e)
{          
        StreamWriter sw = new StreamWriter(@"F:\Logs\log.txt", true);
        sw.WriteLine($"File renamed from {e.OldName} to {e.FullPath}");
        sw.Close();
}
public void OnDelete(object source, FileSystemEventArgs e) //...

private void btnWatch_Click(object sender, EventArgs e)
{
    watcher.Path = Path.GetDirectoryName(txtLocation.Text);
    watcher.Filter = Path.GetFileName(txtLocation.Text);
    watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.Size;
    watcher.EnableRaisingEvents = true;
}

XPath查询xml语言:

XmlDocument xml = new XmlDocument();
xml.Load("../../Demo.xml");
XmlElement e = xml.DocumentElement;
var node = e.SelectSingleNode("Book[Title='韩寒']");
Console.WriteLine(node.SelectSingleNode("Content").InnerText);
xml.Save("../../Demo.xml");

LINQ查询大数集合:

private static int[] GetNumbers(int count)
{
    Random ran = new Random(0);
    int[] result = new int[count];
    for (int i = 0; i < count; i++)
    {
        result[i] = ran.Next();
    }
    return result;
}

static void Main(string[] args)
{
    var nums = GetNumbers(12345678);
    var query = from n in nums
                where n > 1000
                select n;
    Console.WriteLine(query.Count());
    Console.WriteLine(query.Max());
    Console.WriteLine(query.Min());
    // 默认版本.Sum()返回的是int,数值太大导致溢出
    Console.WriteLine(query.Sum(p=>(long)p));
    Console.WriteLine(query.Average());
    Console.ReadKey();
}

LINQ 2:

单值查询 .Distinct()(只选取没有重复的元素)
任意符合 .Any()(任意元素符合条件返回true)
全部符合 .All()(全部元素符合条件返回true)

.First()和.FirstOrDefault()区别:
.First()当条件不满足时,抛出异常
.FirstOrDefault()当条件不满足时,返回一个null

LINQ 3:

集运算符:
.Intersect() 使用默认的相等比较器得出两个序列的交集
.Except() 同上,得出差集
.Union() 同上,得出并集

Join查询:

var orderIds = from n in list select n;
var customers=from n in list
            join m in orderIds on n.Id equals m.Id  //equals 关键词,必须
            select n.Amount+m.Amount;

LINQ TO XML:

//从字符串转换
XDocument d1 = XDocument.Parse(@"
    <customers ID=""A"" City=""NY"" Region=""North American"">
      < order Item = ""Widget"" Price = ""100"" />
      < order Item = ""Tire"" Price = ""200"" />
    </ customers > 
");

XDocument doc = new XDocument(
    //内部有其他元素,则有闭合标签
    new XElement("customers",
        new XAttribute("ID", "A"),
        new XAttribute("City", "NY"),
        new XAttribute("Region", "North American"),
        //内部没有其他元素,则自闭
        new XElement("order",
            new XAttribute("Item", "Widget"),
            new XAttribute("Price", 100)
        ),
        new XElement("order",
            new XAttribute("Item", "Tire"),
            new XAttribute("Price", 200)
        )
    )
);
string path = "../../demo.xml";
doc.Save(path);

XDocument d = XDocument.Load(path);
Console.WriteLine(d);

var query = from n in doc.Descendants("order") select n.Name;
//.Elements()返回第一级子元素
//.Descendants()返回所有子元素
// 重载形式可以指定元素名
//.Attributes()返回当前元素所有特性
欢迎打赏