c#高级编程

113 阅读4分钟

struct结构体

结构体是一种值类型数据

访问修饰符 struct 结构体名字
{
    结构体成员
}

结构体的特点:

1.可带有方法,字段,索引,属性,运算符方法和事件。

2.结构不能定义无参默认构造方法有参构造方法的参数必须包含所有成员字段并且初始化

3.结构可以实现接口,但他不能继承也不能被继承

4.实例化可以使用new,也可以不使用new

值类型不可 赋值为空

枚举Enums

enum声明的集合中,预定义的数据都不可改变,enum是常量的集合 枚举类型中每个元素在底层实现上会使用元素的位置信息作为数据保存在内存中,故枚举类型中每个常量都是整数类型。枚举类型适合与switch结合使用

enum Weekday
        {
            MONDAY = 1,
            TUESDAY,
            WEDNESDAY,
            THURSDAY,
            FRIDAY = 5,
            //FRIDAY变成5后 SATURDAY,SUNDAY自动变为6,7
            SATURDAY,
            SUNDAY
        }


            Weekday firday = Weekday.FRIDAY;

            Console.WriteLine(firday);
            Console.WriteLine((int)firday);
            //FRIDAY,4
            var firday2 = (Weekday)4;
            Console.WriteLine(firday2);
            

泛型generic

//创建一个泛型列表
    //需要带有参数<T>
    public class GenericList<T>
    {
        public void Add(T o)
        {
            throw new NotImplementedException();
        }

        public T this[int index]
        {
            get { throw new NotImplementedException(); }
        }
    }

使用泛型不同于用object,存储的数据类型是它本身,不存在装箱和拆箱的性能问题 泛型也可以指定多个参数

    public class Dictionary<TKey, TValue>
    {
        public void Add(TKey key, TValue value)
        {
            throw new NotImplementedException();
        }

        public TValue get(TKey key)
        {
            throw new NotImplementedException(); 
        }
    }

泛型的限制

泛型可以用类和接口进行限制

//声明泛型参数的类型限制需要使用where
//限制说明使用T:
    public class DiscountCalculator<T> where T : Product
    {

    }

    // where T : IComparable 接口
    // where T : Product 类
    // where T : struct 值类型
    // where T : new() 必须包含默认构造方法

空处理Nullables

C#中值对象不能赋值为空,只声明的对象,C#编译器会赋予默认的初始化数据,bool默认为false,浮点,整数默认为0.

//C#自带的空处理
//Nullable<DataTime> date = null;
语法糖 DataTime? data = null;
//Console.WriteLine(date.GetValueOrDefault()); 输出默认值
//Console.WriteLine(date.HasValue); 输出是否有值
//Console.WriteLine(date.Value);访问变量的数据

C#不可将一个可空的变量直接赋值给一个不可空的变量,但是可以将不可空的变量赋值给可空的变量

DateTime? date = new DateTime(2099, 1, 1);
DateTime date2 = date.GetValueOrDefault();
DateTime? date3 = date2;
//判断date是否有值,有值输出值,无值输出今天
if(date3.HasValue)
{
    Console.WriteLine(date3.GetValueOrDefault());
} else
{
    Console.WriteLine(DateTime.Today);
}
// 语法糖,两个问号,效果相同
var result = date3 ?? DateTime.Today;
Console.WriteLine(result);

??合并运算,??左侧为null时将返回右侧的数据,否则,合并操作符将提取左侧并返回左侧数据

拓展方法extension

拓展方法允许我们向一个已存在的class中添加拓展代码并且不需要修改原class的代码,不需要继承原class

    string hello = "Hello World";
    Console.WriteLine(hello.ShortTerm(2)); // He
    
    public static class StringExtension
    {
        //这里的this代表被拓展的字符串对象
        public static string ShortTerm(this string str, int num)
        {
            return str.Substring(0, num);
        }
    }

动态类型dynamic

dynamic与var的区别: var可以代替程序员在写代码时自动对类型做出判断,使用var意味着在写代码时类型已经被确定了 dynamic则是在程序运行时才会被确定类型,只有在程序走到这一行才知道是什么类型

反射与元数据

反射是.net框架的功能 反射就是通过反射系统,不使用new关键字不知道对象类型的情况下仅通过对象的名称创建一个实例的过程 查看或使用元数据的过程就叫做反射

using System.Reflection;
//程序中所有对象的类的结构说明都会以system.reflection.Type保存
//知道一个类的项目名称,命名空间等信息,就可以使用类的字符串名称在程序运行的时候动态的获得它的类型
//定位程序集
// 定位类                      命名空间.类名,   项目名称
const string classLocation = "HelloWord.List, HelloWord";
// 获取 List 类型对象
Type objectType = Type.GetType(classLocation);

// 通过类型实例化
object obj = Activator.CreateInstance(objectType);

// 调用“Add”方法
MethodInfo add = objectType.GetMethod("Add");
add.Invoke(obj, null);

单元测试,反转控制,依赖注入,泛型的底层实现原理就是反射

异常处理 exception、

try
{

}
catch(DivideByZeroException ex)
{
}
catch(Exception ex)
{
    //c#中有不同的异常类型,exception是所有异常的基类,可以通过捕获不同的异常类型做不同处理
}
finally
{
//无论如何都会执行
}