数往知来C#之 String 集合 深拷与浅拷 序列化<五>

C# 基础经常使用string方法篇

复习、
一、引用类型与值类型
    --》文件的复制与快捷方式的复制
二、垃圾回收
程序员

三、静态与非静态
  --》如何定义静态成员与静态类
  --》如何调用静态成员
算法

四、异常数组

    -》托管与非托管
       -》.net frameworl 
主要分为三个东西:CLR、CTS、类库
     -》由CLR管理的代码就是托管的,不然就是费托管的(如File.Create)
     ->异常是一个类,须要抛出一个异常就要new
  -》thorw关键字,抛出
2、经常使用类库--String
大写的String与小写的string有什么不一样?
  -》能够说两个都同样
  -》String是一个类
  -》构造方法    new string(char [] shs)
2)两个经常使用的属性(Length/Empty(常量))
  -》length   这一点与数组的用法相似
  -》str[0]这个中括号就不叫下标,叫索引
经常使用的方法(索引的使用、ToCharArrray)
不可变性
既然是不可变的,那么多个字符串,结果相同的时候,就没有必要每次生成一个对象(节省资源)
3)字符串拘留池(暂存池)
因为有字符串拘留池的存在,若是代码中有大量的字符串的值相同,那么他们都指向同一个对象,
整个代码中只建立一个对象。
字符串的内部实现与C语言的字符串的实现同样,能够参考 IL Assembly这本书
ide

4)字符串的处理经常使用的
   -》比较
       1)Equals方法
      -》静态的Equals方法
   -》非静态的(string的/object的)
   Equels方法法有三个重载,StringComparison是个枚举 OrdinalIgnoreCase表示不区分大小写比较。
      // Equals方法
            // -> 静态的比较方法(静态方法由类名点出来的)
工具

string str1="abcd";
   string str2="ABCD";
            if (string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase))
            {
                Console.WriteLine("相等");
            }
            else
            {
                Console.WriteLine("不等");
            }
            // -> 非静态(string的,object的)(实例方法是有对象点出来的)
            if (str1.Equals(str2, StringComparison.OrdinalIgnoreCase))
            {
                Console.WriteLine("相等");
            }
            else
            {
                Console.WriteLine("不等");
            }

   

string.Compare方法是静态方法,比较两个字符串大小,比较的的是没一位字符的unicode码,
比较规则:分别从两个字符串的第一位两两相比,若是第一位相等就再比较第二位,知道比出大的为止。
注意:如“22”和“123”相比,此时比较第一个‘2’比‘1’大,那么就后面的不会再比较了,此时“22”比“123”大
学习

string str1="12";
   string str2="23";
     if (string.Compare(str1, str2) > 0)
            {
                Console.WriteLine("大于");
            }
            else
            {
                Console.WriteLine("小于");
            }

   

   -》修整
    Trim()方法,修整字符传收尾的空格,,并将新的字符串返回
Trim(praram char [] chs),去除字符数组中出现的字符
TrimEnd() 去掉右边的
TrimStart() 去掉左边的
   -》检索
增长:
移除
查找
  contains()
  indexof()
  lastindexof()
ui

   -》分割与合并this

   -》格式化
3、StringBuilder
   ->Appand()     追加
   -》AppandLine   追加换行 至关于 Appand(“123\n”)
   ->AppandFramart  格式化
StringBuilder输出的时候记得要ToString()一下
spa

C#  集合篇

1)string.format  格式化字符串(就是挖坑填坑)
能够参考console.writeline(“{0}{1}”,str1,str2);不一样的是conbsole.writeline()是输出,Format是把它做为一个字符串返回。
   -》@符号的两个好处:1)能够取消转义
                   2)写字符串的时候能够换行
2、集合
为何要有集合?
数组不是动态的,他的长度动态的变更,为了拟补这些就有了集合
能够认为,集合就是一个动态的数组,而且提供了一些处理的方法
.net

1)增、
ArrayList里面能够存听任何类型的数据,里面存放的数据类型是object的 (arraylist要引入命名空间  shift+alt+F10)
   arrayList.Add(要添加的数据);  (这是个实例方法)
   arrayList.AddRange(数组);     这里要注意Add方法也能够放一个数组进去,可是不一样的是Add方法是把整个数组当成一个集合的元素存到集合里去,
而AddRange方法是把数组的每一个元素排列放到集合里去。
2)删、
Remove()  把指定的元素删除,若是集合里没有这个元素就会忽略掉,不会报异常
RemoveAt()  把集合里指定下标的元素删除,若是这个下标超出集合的长度就会报异常
3)改、
和数组同样经过下标改。直接赋值
4)查
contains(要查找的元素)
若是集合里有这个元素会返回一个true,不然返回false

5)插入
arrayList.Insert(要插入位置的索引,要插入的数据);

arraylist最大缺点就是Arrayliat是object类型,处理数据须要考虑类型兼容
须要把集合里的数据拿出来的时候须要强制转换,因为是object类型存什么类型的数据均可以,当集合里存的数据多的时候
咱们强制转换就会就会比较麻烦,为了解决这个问题,List<>泛型集合就出现了。

2)Hashtable<键,值>   
   -》Hashtable的出现就是为了让咱们便于查找集合里的数据的,
   -》hashtable里面存的是一个 键 和 值。他们都是object类型的,能够存听任何类型的。
   -》hashtable的键就至关于一个标记,要查找的时候能够经过 hashtable.Contains(要查找的键);方法就能够快速的找到这个键对应着的值(它是经过一个哈希散列算法来实现的)
I、增
      hashtable.Add(键,值);    //hashtable只有一个增长的方法,里面能够听任何类型的数据。
II、删
Remove(键);
    -》咱们知道ArrayList是经过下标来删除的,那么 咱们的hashtable也是相同的原理,hashtable的键就至关于arraylist的下标,
若是把键改为0、一、二、三、四、5........那么就至关于一个ArrayList,那么能够获得结论,hashtable[键] 经过中括号 键来删除。
3、泛型集合
List<T>   这个尖括号里写什么类型这个集合就存什么类型的数据
  -》list就至关于一个规定好存放类型的ArrayList,
  ->当咱们规定好类型后就能够解决类型兼容的问题了,从几何里取数据时就方便多了。
  List的增、删、改、查方法跟ArrayList同样。
Dictionary<键,值> 
    ->Dictionary对应的就是hashtable,咱们能够规定好键和值的类型,使用起来更加的方便
    -》遍历的三种方法

foreach (string item in dic.Keys)   //经过键来遍历
            {
                Console.WriteLine(item);
                Console.WriteLine(dic[item]);
            }

            foreach (Person item in dic.Values)  //经过值来遍历
            {
                Console.WriteLine(item);
            }

            foreach (KeyValuePair<string,Person> item in dic)  //咱们有时候遍历的时候要同时用到集合的键和值,就能够经过这个方法
            {                                                   //KeyValuePair也是一个集合
                Console.WriteLine(item.Key + " "+item.Value);
            }


遍历集合用foreach,  ArrayList和hashtable使用要引入命名空间,而List和Dictionary不用,能够看出微软提倡咱们用 List和Dictionary

2、foreach  (能够遍历任何实现了IEnumerble接口的对象)
  foreach(临时数据类型 临时变量 in 要遍历的集合)
  {
     //将临时变量做为遍历的数据使用
  }
要知道临时数据类型是什么类型的能够先写个var 而后在下面设个断点,再把光标放到var上去,就能够获得当前遍历的集合是什么类型了
尽可能不要用var

4、装箱与拆箱
值类型转换为引用类型就是装箱
应用类型转换为值类型就是拆箱

对值类型装箱保持不变性,对引用类型不保持保持相关性()

Dotnet学习_递归篇

3、递归

递归就是调用本身

--》怎么调用?(递推关系)

--》何时跳出

等差数列

           2   4   6   8   10  ...

求第n项

               2n

           Func(n) = Func(n-1) + 2

           Func(n) = (Func(n-1-1)+2)+2

。。。

           Func(n) = (Func(1)。。。)。。。+2

写递归

      --》首先要找到递推关系

      --》临界条件

wps71DD.tmp

wps720D.tmp

 

小练习_神探福尔摩斯小说

private void Form1_Load(object sender, EventArgs e)
        {
            //先添加一个根节点
            TreeNode tn = tvwDir.Nodes.Add("神探福尔摩斯-柯南.道尔");
            //得到文件的路径
            string path= Path.GetFullPath ("txt");
            RecAdd(tn, path);
        }
        private void RecAdd(TreeNode tn, string path)
        {
            //得到这个路径下的全部子目录
            string [] dirs = Directory.GetDirectories(path);
            //得到这个路径下的全部子文件
            string[] files = Directory.GetFiles(path);
            //循环把全部的子目录添加到父节点下
            foreach (string item in dirs)
            {
                //从绝对路径里提取文件名
                string file= Path.GetFileNameWithoutExtension(item);
                TreeNode tn1= tn.Nodes.Add(file);//目录名添加到父节点下
                //递归调用,由于不知道子目录下还有多少个子目录,因此递归调用
                RecAdd(tn1, item);
            }
            //循环添加全部的子文件到父节点下
            foreach (string item in files)
            {
                //一样的须要对绝对路径作一下处理,提取文件名
                string file = Path.GetFileNameWithoutExtension(item);
                TreeNode tn2= tn.Nodes.Add(file);//文件名添加到父节点下
                tn2.Tag = item;
                //tag属性石用来存储程序员须要使用的任何数据
                //把绝对路径保存到刚添加的节点的tag属性下,用于后面读取文件里的内容
            }
        }
        private void tvwDir_AfterSelect(object sender, TreeViewEventArgs e)
        {
            TreeNode tn= e.Node ;//先获取选中的节点
            if (tn.Tag !=null)//判断tag属性是否是空
            {
                txtContans.Text = File.ReadAllText(tn.Tag .ToString (),Encoding .Default );
            }
        }

C#  深拷和浅拷篇

2、深拷与浅拷
拷就是拷贝、复制的意思
      --》深拷和浅拷是指堆空间里的对象和引用类型的拷贝,而值类型不存在深拷和浅拷,由于值类型只是把值给复制了一份。
浅拷
   --》浅拷,只要有一个引用类型没有被复制就是浅考,(复制就是产生了一个彻底没有关系的对象,而这个对象里德值是被复制过来的)
     

class Mark
    {
        string _name;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
    }
    class MyClass
    {
        string _name;
        Mark mark;
        public Mark Marks
        {
            get { return mark; }
            set { mark = value; }
        }
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        public MyClass Coby()
        {
            MyClass temp=new MyClass ();
            temp.Name = this.Name;
            temp.mark = new Mark();
            temp.mark.Name = this.mark.Name;
            return temp;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyClass m1 = new MyClass();
            m1.Name = "张三";
            m1.Marks = new Mark();
            m1.Marks.Name = "哈哈哈";
            MyClass m = m1;   //这里只是把m1的引用复制了一份赋给了m   并无复制m1里的对象也没有复制引用类型因此既不是深考也不是浅考
            MyClass m2 = new MyClass();  //浅考
            m2.Name = m1.Name;
            m2.Marks = m1.Marks;//这里是把m1Marks里的对象复制了,m1.marks存的引用又复制了一份赋给m2.marks此时他们都是指向了堆空间里的另外一个对象mark,引用类型没有被彻底复制在mark这里断开了,因此是浅考
            MyClass m3 = new MyClass();
            m3.Name = m1.Name;
            m3.Marks = new Mark();
            m3.Marks.Name = m1.Marks.Name;//这里m3是从新New一个对象,而后把m1.marks.name的值复制给m3.marks.name,他们是两个彻底不同的对象,此时m1里的引用类型被m3彻底的复制了一份,因此叫深考,
                                                                   //只要 全部的引用类型都被复制了没有一个被断开就是深考
        }

wps722D.tmp

C#  序列化篇

1、序列化
为何要序列化?    --》为了把内存里的数据写到硬盘里。
序列化首先 第一步:给类加一个标签,标记为能够被序列化,要序列化的对象类与父类均需标记

[Serializable]   //标记 (特性的意思)
Class myClass
{
}
     static void Main(string[] args)
        {
            #region 传统方法
            //Student stu = new Student();
            //stu.Name = "张三";
            //stu.Sex='男';
            //stu.Age = 20;
            ////将student对象存到
            //StringBuilder sb = new StringBuilder();
            //sb.AppendLine(stu.Name );
            //sb.AppendLine(stu.Age.ToString () );
            //sb.AppendLine(stu.Sex .ToString ());
            //File.WriteAllText("E:\\sb.txt", sb.ToString());
            //string []input= File.ReadAllLines("E:\\sb.txt");
            //Student s=new Student ();
            //s.Name = input[0];
            //s.Age =Convert .ToInt32 ( input[1]);
            //s.Sex = Convert.ToChar(input[2]);
            #endregion
            List<Student> list = new List<Student>();
            list.Add(new Student ("张三1",20,''));
            list.Add(new Student("张三2", 20, ''));
            list.Add(new Student("张三3", 20, ''));
            list.Add(new Student("张三4", 20, ''));
            list.Add(new Student("张三5", 20, ''));
            list.Add(new Student("张三6", 20, ''));
            list.Add(new Student("张三7", 20, ''));
            list.Add(new Student("张三8", 20, ''));
            list.Add(new Student("张三9", 20, ''));
            #region 荣誉代码
            //using (FileStream file = new FileStream("E:\\1.dat", FileMode.Create, FileAccess.Write))
            //{
            //    BinaryFormatter bin = new BinaryFormatter();
            //    bin.Serialize(file, list);
            //}
            //Console.WriteLine("序列化完成");
            //using (FileStream wfile = new FileStream("E:\\1.dat", FileMode.Open, FileAccess.Read))
            //{
            //    BinaryFormatter bin=new BinaryFormatter ();
            //    Student s = (Student)bin.Deserialize(wfile);
            //}
            #endregion
            //序列化
            //首先须要一个写得流
            using (FileStream filewrite = new FileStream("E:\\1.dat", FileMode.Create, FileAccess.Write))
            {
                //再须要一个工具
                BinaryFormatter bin = new BinaryFormatter();
                bin.Serialize(filewrite, list);  //第一个是流,第二个是对象
            }
            //反序列化
            //首先也须要一个读的流
            using (FileStream fileread = new FileStream("E:\\1.dat", FileMode.Open, FileAccess.Read))
            {
                //再须要一个工具
                BinaryFormatter fbin = new BinaryFormatter();
                List <Student > s = (List <Student >)fbin.Deserialize(fileread);
            }
            Console.WriteLine("完成");
        }


序列化的一个应用---保存窗体上一次关闭时的位置
--》首先写一个方法,保存窗体的位置(窗体的左上角的坐标)和窗体的长和宽,在关闭窗体的时候调用这个方法。(写在Dispose方法里 关闭窗体时都会调用这个方法)
  

protected override void Dispose(bool disposing)
        {
            //调用保存窗体关闭时的位置大小
            Save();
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
--》而后要一个类,这个类里面有两个字段 来存储窗体的location和size属性,把这儿两个属性分别赋值给这个类的两个字段
    class MyPoint
    {
        Point mPoint;
        Size mySize;
        public Point  MPoint
        {
            get;
            set;
        }
        public Size  MySize
        {
            get;
            set;
        }
    }


--》而后序列化把数据写到硬盘里保存,当窗体关闭的时候调用这个方法就保存了窗体关闭时的位置和大小。
--》再写一个方法反序列化,把存到硬盘里德数据再拿出来,写窗体的 Lode事件(窗体启动前都会执行lode事件,lode事件通常都用来初始化),
把定义类的两个字段里存的数据再赋给窗体。
   

private void Save()
        {//须要一个流
            using (FileStream filewrite = new FileStream("location.dat", FileMode.Create, FileAccess.Write))
            {
                //new一个MyPoint类用来存储窗体的位置大小
                MyPoint mypoint = new MyPoint();
                mypoint.MPoint = this.Location;//把窗体的位置赋给字段(窗体的左上角的point)
                mypoint.MySize = this.Size;//把窗体的大小赋给字段
                //须要一个序列化的工具
                BinaryFormatter bin = new BinaryFormatter();
                //开始序列化
                bin.Serialize(filewrite, mypoint);
            }
        }
        private void ReadLocatoin()
        {
            if (File.Exists("location.dat"))//判断一下窗体的位置大小被改变了没有,若是改变了会产生一个"location.dat"文件
            {
                //须要一个流
                using (FileStream fileread = new FileStream("location.dat", FileMode.Open, FileAccess.Read))
                {
                    //须要一个反序列化的工具
                    BinaryFormatter bin = new BinaryFormatter();
                    //开始反序列化
                    MyPoint p = (MyPoint)bin.Deserialize(fileread);
                    //把窗体的启动起始位置设置为自定义
                    this.StartPosition = FormStartPosition.Manual;
                    this.Location = p.MPoint;
                    this.Size = p.MySize;
                }
            }
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            ReadLocatoin();
        }

//最近工做事情多,本系列下章应该会延时。

相关文章
相关标签/搜索