C#学习笔记(1)

本文是C#学习笔记,介绍了命名空间、Console类、int.Parse、for each循环、ref和out关键字、params关键字、数组、属性、继承与重写、抽象类和接口、异常处理、结构体、枚举、XML支持、C#3.0新特性,包括自动属性、初始化简化、扩展方法等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习动机:

辅导员要求我写一个抽奖软件,正好借此机会学一下C#


学习网址:

点这里


笔记内容


namespace
Namespace is a collection of classes. 在程序开头using引入的就是namespae。例如,我们使用的Console类就是在System这个namespace里的。
每个程序自身有一个默认的namespace,我们书写的类就是包含在它里面的。

Console类
与java不同,C#的IO是通过Console类完成的(其实大同小异)
两个方法:ReadLine WriteLine

int的Parse
int一方面是C#的基本数据类型,另一方面又是一个类?
拥有Parse这个方法

for each
类似C++的range for,对容器进行遍历
基本格式:

foreach (string i in list)
    Console.WriteLine(i);

ref out关键字
引用是为了解决函数只能够返回一个值的问题(matlab多好)
与C++不同,C#的函数如果需要传递引用,需要同时在函数调用和函数声明时加上ref关键字。
out关键字和ref关键字用法几乎相同,唯一区别为ref的实参需要初始化,而out不用;但是在方法中必须为这个变量赋值。
例:

static void Main(string[] args)
{
    int number = 20;
    AddFive(ref number);
    Console.WriteLine(number);
    Console.ReadKey();
}

static void AddFive(ref int number)
{
    number = number + 5;
}

params关键字
在参数为类似String[]时,调用该函数形式较为复杂:

testFun(new String[] { "myk", "qingye" });

此时加上params关键字,可以用比较简单的方式调用该函数:

static void testFun(params String[] args)
 {


 }
 testFun("myk", "qingye");

甚至可以传递空的参数
一个函数中只能出现一个prams关键字;当参数中出现params参数和其他参数的时候,params参数需要放在最后。

数组
数组初始化:

int[] a = new int[5] { 1, 2, 3, 4, 5 };

数组排序:

int[] a = new int[5] { 1, 2, 3, 5, 4 };
Array.Sort(a);

属性
C#中,属性可以用来控制字段的写入、写出(但他并不是字段)。
属性有get和set操作,可以只有一个使得它成为只读/只写的。get操作决定了当我们访问这个属性的时候能够得到什么(这个时候属性扮演一个字段的角色);set操作决定了当我们给这个属性赋值的时候,会进行什么(这个时候属性扮演一个方法的角色)。
属性可以设置public private等权限。
下面是一个例子:

        public string Color
        {
            get
            {
                return color;
            }
            set
            {
                color = value+"test";
            }
        }

此处color是之前定义的一个private字段。在给Color属性赋值后,color会改变。
重要!几个概念的区分
field(字段):类似C++的私有变量。
property(属性):用来读和写字段的一种方便的形式。

这里我要特别提一下,关于属性和字段,网络上能够找到数以万计的博文,但几乎都是一个模子出来的,都没有把这两个简单的概念讲清楚。在看了这篇博客后才彻底搞清楚,不得不感慨,通过博客学不到什么东西,还是应该老老实实去看书。
一篇很好的博客

C#的继承和重写
C#中的继承和重写类似c++,只是语法规则有些不同,下面是例子:

    public class Animal
    {
        public virtual void bark()
        {
            Console.Out.WriteLine("An animal is barking!");
        }
    }
    public class Dog:Animal
    {
        public override void bark()
        {
            Console.Out.WriteLine("A dog is barking!");
        }
    }
C#不支持多继承。

C#中的抽象类
和java一样C#支持抽象类。抽象类不允许被实例化。

    abstract class FourLeggedAnimal
    {
        public virtual string Describe()
        {
            return "Not much is known about this four legged animal!";
        }
    }

    class Dog : FourLeggedAnimal
    {

    }

C#中的抽象方法
抽象方法只能定义在抽象类中:

abstract class FourLeggedAnimal
{
    public abstract string Describe();
}

抽象方法的作用,是使得抽象类对于它的子类产生这样一种约束:这个方法必须被重写(必须实现这个方法)。
C#中的接口
类似抽象类,接口不允许实例化,不允许出现字段(field);更为概念化(conceptual)的,接口中不允许出现实现了的方法。
接口类似于一个只有抽象方法的抽象类。它定义了一种规范/标准。
接口中可以有属性。
C#虽然不允许多继承,但允许一个类继承多个接口。
接口中 权限修饰符全部无效(有了会报错),全都是默认public。
下面是一个接口的范例:

    interface IAnimal
//以I开头,编码习惯
    {
        void Describe();//定义了一个规范,所有继承自本接口的类必须实现这个接口
        string Name//所有继承自本接口的类必须实现这个属性
        {
            get;
            set;
        }
    }

接下来介绍一下C#自带的IComparable接口以及is as强制类型转换。

is检查一个对象是否兼容于指定的类型,并返回一个Boolean值:true或>
as进行强制类型转换,如果失败,返回一个null

异常的抛出和处理
try语句块捕捉异常;一旦发现异常就退出try语句块
catch语句块如果没有参数则一旦捕捉到异常就执行;有参数则把异常赋值给这个参数
没什么好说的,直接上代码:

int[] numbers = new int[2];
try
{
    numbers[0] = 23;
    numbers[1] = 32;
    numbers[2] = 42;

    foreach(int i in numbers)
        Console.WriteLine(i);
}
catch
{
    Console.WriteLine("Something went wrong!");
}
Console.ReadLine();

catach可以捕捉到具体的异常是什么:

catch(Exception ex)
{
    Console.WriteLine("An error occured: " + ex.Message);
}

我们可以这样得到异常类:

Console.WriteLine("An error occured: " + ex.GetType().ToString());

如果我们需要对特定的异常做处理,可以这么写:

catch(IndexOutOfRangeException ex)
{
    Console.WriteLine("An index was out of range!");
}
catch(Exception ex)
{
    Console.WriteLine("Some sort of error occured: " + ex.Message);
}

上文的代码中,意思是第一个catch语句块先捕捉IndexOutOfRangeException 异常类,如果捕捉到了,这个异常类就不会被第二个catch语句块捕捉了。
注意这两个catch语句的顺序不能颠倒,因为所有异常类都是Exception类。

finally语句块
finally语句块的特性是,这个语句块的内容一定会被执行。(当然异常必须被处理)

C#中的结构体
C#中,结构体的实例在栈上,类的实例在堆上。
在向函数传递参数时,结构体是按值传递的(而不是传引用)。
C#中的结构体的字段不能有初始值;在构造函数中必须把所有字段都赋值。
结构体不参与继承:不能被继承,也不能继承自其他结构体或类。但是可以实现接口。


C#中的枚举
定义一个枚举:

public enum Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }

使用枚举:

Days day = Days.Monday;

使用神奇的Enum类:

static void Main(string[] args)
{
    string[] values = Enum.GetNames(typeof(Days));
    foreach(string s in values)
        Console.WriteLine(s);

    Console.ReadLine();
}

C#对XML的支持
xml可以用来自定义样式

using System.Xml;

这个namespace中包含了很多C#自带的对xml读写的类。

利用XmlReader类读取xml文件
下面是一个示例:

using System;
using System.Text;
using System.Xml;

namespace ParsingXml
{
    class Program
    {
        static void Main(string[] args)
        {            
            XmlReader xmlReader = XmlReader.Create("http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml");
            while(xmlReader.Read())
            {
                if((xmlReader.NodeType == XmlNodeType.Element) && (xmlReader.Name == "Cube"))
                {
                    if(xmlReader.HasAttributes)
                        Console.WriteLine(xmlReader.GetAttribute("currency") + ": " + xmlReader.GetAttribute("rate"));                    
                }
            }
            Console.ReadKey();
        }
    }
}

C#3.0的新特性

自动属性
不用自己写getter和setter了!一句话就可以:

public string Name { get; set; }

编译器甚至会自动帮你生成一个字段用来存储这个Name!

更方便的初始化

Car car = new Car { Name = "Chevrolet Corvette", Color = Color.Yellow };

这是和自动属性配合使用的;通常我们对于自动属性都会在new对象后手动赋值,这个新特性使得我们可以直接在curly brace中对这些属性赋值。
这个特性甚至可以嵌套:

class Car
{
    public string Name { get; set; }
    public Color Color { get; set; }
    public CarManufacturer Manufacturer { get; set; }
}

class CarManufacturer
{
    public string Name { get; set; }
    public string Country { get; set; }
}

Car car = new Car { 
                Name = "Chevrolet Corvette", 
                Color = Color.Yellow, 
                Manufacturer = new CarManufacturer { 
                    Name = "Chevrolet", 
                    Country = "USA" 
                } 
            };

容器初始化的简化写法/添加元素的简化写法

没什么好说的,直接上代码:

List<Car> cars = new List<Car>();
cars.Add(new Car { Name = "Corvette", Color = Color.Yellow });
cars.Add(new Car { Name = "Golf", Color = Color.Blue});

下面的写法可就牛逼了:

List<Car> cars = new List<Car> 
{ 
    new Car { Name = "Corvette", Color = Color.Yellow },
    new Car { Name = "Golf", Color = Color.Blue}
};

扩展方法
这个可是真的牛逼了,可以直接给一个类扩展方法而且不用修改类
事实上,扩展方法并不是真的给类扩展了方法,而是另外定义了一个函数(这里用函数更加妥当),接受一个对象,对它进行某个操作,同时通过编译器的小trick,使得我们调用这个函数的时候,可以像调用这个类的方法一样调用。

代码:

//静态类加静态方法,等同于函数
public static class MyExtensionMethods
{
    public static bool IsNumeric(this string s)
    {
        float output;
        return float.TryParse(s, out output);
    }
}


string test = "4";
if (test.IsNumeric())//类似类的方法调用
    Console.WriteLine("Yes");
else
    Console.WriteLine("No");

注意静态类和静态方法以及this关键字。

C#文件操作
C#的文件操作相关类都在

using System.IO;

下面是一个简单的文件IO程序:

using System;
using System.IO;

namespace FileHandlingArticleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            if (File.Exists("test.txt"))
            {
                string content = File.ReadAllText("test.txt");
                Console.WriteLine("Current content of file:");
                Console.WriteLine(content);
            }
            Console.WriteLine("Please enter new content for the file:");
            string newContent = Console.ReadLine();
            File.WriteAllText("test.txt", newContent);
        }
    }
}

具体用到的类是File类。涉及的方法有:
Exists方法检测指定的路径的文件是否存在。如果是相对路径,就到项目目录下的/bin/Debug找。(可以在vs中设置,最后在exe文件所在目录)
ReadAllText方法一次性读入文本文件的所有内容。
WriteAllText方法一次性写入文本文件。(覆盖写)
AppendAllText方法一次性写入文本文件,追加写。
Environment.NewLine方法为一行。

C#的using语句
using语句在C#中一个重要的作用是:定义一个范围,在范围结束时处理对象。
使用C#的输入输出流进行IO操作
代码:

Console.WriteLine("Please enter new content for the file - type exit and press enter to finish editing:");
using(StreamWriter sw = new StreamWriter("test.txt"))
{
    string newContent = Console.ReadLine();
    while(newContent != "exit")
    {
        sw.Write(newContent + Environment.NewLine);
        newContent = Console.ReadLine();
    }
}

如何判断字符串是空的
String类有一个静态成员变量:

String.Empty

所以判断一个字符串非空:

if(newFilename != String.Empty)

使用C#操控文件和目录
删除文件

if(File.Exists("test.txt"))
{
    File.Delete("test.txt");
    if(File.Exists("test.txt") == false)
        Console.WriteLine("File deleted...");
}
else
    Console.WriteLine("File test.txt does not yet exist!");
Console.ReadKey();

删除目录:

if(Directory.Exists("testdir"))
{
    Directory.Delete("testdir",true);
//true means delete the directory recursively 
    if(Directory.Exists("testdir") == false)
        Console.WriteLine("Directory deleted...");
}
else
    Console.WriteLine("Directory testdir does not yet exist!");
Console.ReadKey();

重命名目录
参照Linux,使用mv命令即可。

if(Directory.Exists("testdir"))
{
    Console.WriteLine("Please enter a new name for this directory:");
    string newDirName = Console.ReadLine();
    if(newDirName != String.Empty)
    {
        Directory.Move("testdir", newDirName);
        if(Directory.Exists(newDirName))
        {
            Console.WriteLine("The directory was renamed to " + newDirName);
            Console.ReadKey();
        }
    }
}              

创建一个新的目录

Console.WriteLine("Please enter a name for the new directory:");
string newDirName = Console.ReadLine();
if(newDirName != String.Empty)
{
    Directory.CreateDirectory(newDirName);
    if(Directory.Exists(newDirName))
    {
        Console.WriteLine("The directory was created!");
        Console.ReadKey();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值