基础知识总结(C#)

   1.值类型的数据保存在内存的栈中;引用类型数据存储在内存的堆中,而内存单元只存放堆中对象的地址。

   2.值类型存取速度快,引用类型存取速度慢

   3.值类型表示实际数据,引用类型表示存储在内存堆中数据的地址或引用

   4.值类型继承自System.ValueType,引用类型继承自System.Object

   5.栈的内存分配是自动释放;而堆在.net 中会有GC来释放

堆与栈简单理解

C#程序在CLR上运行的时候,内存从逻辑上划分两大块:栈,堆。这俩基本元素组成我们C#程序的运行环境。

   1、堆与栈概念介绍
        堆:在c里面叫堆,在c#里面其实叫托管堆。

        栈:就是堆栈,因为和堆一起叫着别扭,就简称为栈。

    2、托管堆
         托管堆不同于堆,它是由CLR(公共语言运行库(Common Language Runtime))管理,当堆中满了之后,会自动清理堆中的垃圾。所以,做为.net开发,我们不需要关心内存释放的问题。

   3、内存堆栈与数据堆栈
        内存堆栈:存在内存中的两个存储区(堆区,栈区)。
           栈区:存放函数的参数、局部变量、返回数据等值,由编译器自动释放。
           堆区:存放着引用类型的对象,由CLR释放。
       数据堆栈:是一种后进先出的数据结构,它是一个概念,主要是栈区。

   

装箱和拆箱

        装箱:将值类型转为引用类型,将栈内存搬到堆内存里。
        拆箱:将引用类型转为值类型,将堆内存搬到值内存里。

        这里的引用类型用object。

        好处:不确定类型可以方便参数的存储和传递。
        坏处:内存迁移,性能消耗,所以要少用。

    注意:

        装箱、拆箱只会发生在值类型和引用类型之间。

        类的继承关系中的向上或向下转型并不会引起装箱、拆箱。例如,如果有一个类 Child 继承  自另一个类 Parent,将 Child 类型的对象转换为 Parent 类型并不会导致装箱。这只是在内存中创建了一个指向同一对象的父类引用,而不会创建新的对象。

        如何避免装箱拆箱操作

        

  1. 使用泛型集合

        使用泛型集合(例如 List<T>Dictionary<TKey, TValue> 等)而不是非泛型集合(如 ArrayListHashtable 等),因为泛型集合只能存储指定类型的元素,不会引起装箱和拆箱操作。

     2.避免将值类型转换为引用类型

  •         避免将值类型转换为引用类型,特别是在性能敏感的代码路径中。
    • 尽量使用泛型类型参数而不是 object 类型,以避免装箱。

    3.使用 as 操作符

  •         如果你确实需要将引用类型转换为值类型,并且不确定是否会引起拆箱异常,可以使用 as 操作符进行安全转换。

显示转换和隐式转换

        

  1. 隐式转换(Implicit Conversion)
  • 隐式转换是指在不需要额外操作的情况下,将一种数据类型转换为另一种数据类型。
  • 隐式转换通常发生在转换目标类型的范围更大、更精确的情况下,这种转换是安全的,不会导致数据丢失。
  • 例如,将 int 类型转换为 long 类型是一种隐式转换,因为 long 类型的范围比 int 类型更大,不会导致数据丢失
  • 例如,将子类转换成父类。
    int a = 10;
    long b = a; // 隐式转换
    
    class Parent {}
    class Child : Parent {}
    
    Child child = new Child();
    Parent parent = child; // 隐式向上转型
    

      2.显示转换(Explicit Conversion)

  • 显示转换是指在需要额外操作的情况下,将一种数据类型转换为另一种数据类型。
  • 显示转换通常发生在转换目标类型的范围比源类型更小、更不精确的情况下,这种转换可能导致数据丢失,需要程序员显式指定进行转换。
  • 例如,将 double 类型转换为 int 类型是一种显示转换,因为 double 类型的范围比 int 类型更大,可能导致数据精度丢失,需要程序员显式指定进行转换。
  • 例如,父类转成子类。
    double c = 10.5;
    int d = (int)c; // 显示转换
    
    class Parent {}
    class Child : Parent {}
    
    Parent parent = new Child();
    Child child = (Child)parent; // 显式向下转型
    
     解释var 和 dynamic

1.var  

  • var 关键字用于声明隐式类型变量。编译器会根据变量的初始表达式推断琪类型,并在编译时将其替换成具体的类型。
  • var  其类型是在编译时确定,一旦确定了类型,就不能在改变。
  • var适用于静态类型语言的情况。
    var number = 10; // 编译器会将 number 推断为 int 类型
    var name = "John"; // 编译器会将 name 推断为 string 类型
    

2.dynamic

  • dynamic 关键字用于声明动态类型变量。动态类型在编译时不会进行类型检查,而是在运行时根据实际情况来确定类型。

  • dynamic 变量的类型是在运行时确定的,这意味着你可以在运行时改变变量的类型

  • dynamic 可以用于弱类型语言(如JavaScript)交互,或者用于编写需要在运行时处理各种类型的代码。

    dynamic dynamicVar = 10; // dynamicVar 在运行时被确定为 int 类型
    dynamicVar = "John"; // dynamicVar 在运行时被改变为 string 类型
    
    c#中匿名类型是什么?

匿名类型是一种特殊的类型,他允许您在不事先定义类的情况下穿件对象。匿名类型通常用于零食存储一组相关的数据,并且在使用LINQ查询等情况下非常有用。

匿名类型的特点包括:

  • 无需显示定义类:您不需要显示定义一个类来创建匿名类型。相反,您可以使用 new 关键字创建一个对象,并通过初始化语法为期提供属性的值。
  • 自动属性:匿名类型属性是自动属性,编译器会根据初始化器中提供的属性名称和类型自动生成属性。
  • 只读:匿名类型的属性是只读的,一旦创建就不能修改。
  • 用于临时数据:通常用语存储一组相关的数据。
    var person = new { Name = "John", Age = 30 };
    Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
    

    匿名类型的一些限制:

  • 不能在方法之外的作用域使用

  • 不能添加新的成员或扩展匿名类型

  • 属性是只读的,不能更改其值。

多线程及其不同的状态

多线程允许在同一程序中并发多个任务。每个现成都有自己的执行路径,可以同时执行不同的代码段。线程可以处于不同的状态。主要包含以下几种状态:

  • Unstarted(未启动):线程对象被创建但尚未启动。可以调用Thread.Start() 方法来启动线程。
  • Running(运行中):线程正在执行其代码。
  • stopped(已停止):线程已经执行完毕,结束运行。
  • Suspended(暂停):线程暂停执行,等待恢复执行。
  • Background(后台):后台线程是一种特殊的线程,他在主线程结束时自动结束,即使他没有执行完。可以通过设置“IsBackground”属性为 ‘True’来创建后台线程。
泛型是什么?

泛型是一种编程特性,允许您编写可重用,类型安全的代码,而无需为每种数据类型编写不同的实现。通过泛型,可以编写具有参数化类型的类、接口和方法,以便他们能够在编译时使用不同的数据类型。

泛型的好处:

  • 类型安全:泛型允许在编译时检查类型,从而减少了运行时类型错误的可能性
  • 代码重用:通过编写泛型代码,可以编写一次代码,并将其应用于多种不同类型的数据,从而提高了代码的可重用性。
  • 性能优化:泛型允许编译器生成特定的数据类型的代码,从而避免了装箱和拆箱操作,并提高了性能。

示例:

// 泛型类示例
public class GenericList<T>
{
    private T[] data;

    public GenericList(int capacity)
    {
        data = new T[capacity];
    }

    public void Add(T item)
    {
        // 添加元素到列表
    }

    // 其他方法...
}

// 使用泛型类
GenericList<int> intList = new GenericList<int>(10);
intList.Add(5);
intList.Add(10);

GenericList<string> stringList = new GenericList<string>(5);
stringList.Add("Hello");
stringList.Add("World");
 可空类型

可空类型是C#语言中的一个特性,他允许基本数据类型具有额外的null值。通常情况下,c#中的值类型(如int、float、bool等)是不允许复制为null的,但通过可空类型,可以在值类型的基础上添加一个null值。

使用场景:

  •  数据库处理:数据库中某些字段允许为空。
  • api和外部数据:从外部接口或数据源中获取的数据类型可能包含缺失值,通过可空类型,可以更好表示这些数据。
  • 业务逻辑:在某些业务场景中,值可能是位置的或不适用的,可使用可空类型表示。

示例:

int? nullableInt = null;
float? nullableFloat = 3.14f;

if (nullableInt.HasValue)
{
    Console.WriteLine("nullableInt has value: " + nullableInt.Value);
}
else
{
    Console.WriteLine("nullableInt is null");
}

if (nullableFloat.HasValue)
{
    Console.WriteLine("nullableFloat has value: " + nullableFloat.Value);
}
else
{
    Console.WriteLine("nullableFloat is null");
}
goto语句介绍
  • goto 语句由关键字 goto 后跟一个标签名称组成,通过标签名称指定跳转的位置。

  • 可以在方法的任何地方放置标签,并且可以多次使用相同的标签。

示例

 /// <summary>
        /// 使用goto进行代码重试示例
        /// </summary>
        public static void GotoRetryUseExample()
        {
            int retryCount = 0;
            for (int i = 0; i < 10; i++)
            {
            retryLogic:
                try
                {
                    //模拟可能出错的操作
                    Random random = new Random();
                    int result = random.Next(0, 2);

                    if (result == 0)
                    {
                        throw new Exception("Error occurred");
                    }

                    Console.WriteLine("Operation successful on attempt: " + retryCount);
                }
                catch (Exception ex)
                {
                    retryCount++;
                    if (retryCount < 3)
                    {
                        Console.WriteLine("Error occurred, retrying...");
                        goto retryLogic; //跳转到重试逻辑
                    }
                    else
                    {
                        Console.WriteLine("Max retry limit reached.");
                        return;
                    }
                }
            }
        }
 /// <summary>
        /// goto正常输出使用示例
        /// </summary>
        public static void GotoGeneralUseExample(int num)
        {
            if (num < 0)
            {
                goto LessThanZero;
            }
            else if (num == 0)
            {
                goto EqualToZero;
            }
            else
            {
                goto GreaterThanZero;
            }

        LessThanZero:
            Console.WriteLine("数字小于零");
            goto End;

        EqualToZero:
            Console.WriteLine("数字等于零");
            goto End;

        GreaterThanZero:
            Console.WriteLine("数字大于零");
            goto End;
        End:
            Console.WriteLine("End...");
        }

注:虽然在某些情况下,goto 可以简化代码结构,但是它被广泛认为是一种不良的编程实践,因为它经常导致代码难以理解和维护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值