C#易错易混淆知识总结(三)--{结构}{静态成员和实例成员}

一,C#中结构

在C#中可以使用struct关键字来定义一个结构,级别与类是一致的,写在命名空间下面。

1)结构中可以定义属性,字段,方法和构造函数。示例代码如下:

复制代码
//定义结构
    struct Point
    {
       

        //定义字段
        private int x;

        //封装字段
        public int X
        {
            get { return x; }
            set { x = value; }
        }
        
        //定义方法
        public void Result()
        {
            
        }

        //定义构造函数
        public Point(int n)

        {
            this.x = n;
            //Console.WriteLine(n);
        }

    }
复制代码

那么,声明类与结构的区别有哪些呢?

①无论如何,C#编译器都会为结构生成无参数的构造函数;

当我们显式的定义无参数的构造函数,编译时会报错,结果如下:

编译器告诉我们,结构不能包含显式的无参数的构造函数

但是这样编写代码时,编译器却不报错,代码如下:

//这里可以调用无参数的构造函数
            Point p = new Point();
            Console.WriteLine(p.GetType());

运行结果如下:

 

 

 虽然结构不能显式的声明无参数的构造函数,但是程序员却可以显式的调用结构的无参数的构造函数,说明C#编译器无论如何都会为结构生成无参数的构造函数。

②结构中的字段不能赋初始值;

 

 

 ③在结构的构造函数中必须要对结构体的每一个字段赋值;

当我们不声明显式的构造函数时,可以不对成员字段赋值,但是一旦声明了构造函数,就要对所有的成员字段赋值

 

 

 对所有的成员字段赋值,代码如下:

//定义构造函数
        public Point(int n)
        {
            this.x = n;
            //Console.WriteLine(n);
        }

④在构造函数中对属性赋值不认为对字段赋值,属性不一定去操作字段;

 

 

 所以在构造函数中我们对字段赋初始值的时候,正确的代码应该是

复制代码
//定义构造函数
        public Point(int n)
        {
            //正确的可以对字段赋初始值
            this.x = n;

            //在构造函数中对属性赋值,但是不一定操作字段
            this.X = n;
            //Console.WriteLine(n);
        }
复制代码

2)结构体的数值类型问题

C#中的结构是值类型,它的对象和成员字段是分配在栈中的,如下图:

 

 

 那么当我们写了如下的代码,内存中发生了什么呢?

//这里可以调用无参数的构造函数
            Point p = new Point();
            //为p的属性赋值
            p.X = 100;
            //将p赋值给Point新的对象p1
            Point p1 = p;

Point p1=p发生了什么呢?情况如下:

 

 

 声明结构体对象可以不使用“new”关键字如果不使用“new”关键字声明结构体对象,因为没有调用构造函数,这个时候结构体对象是没有值的。而结构的构造函数必须为结构的所有字段赋值,所以通过"new"关键字创建结构体对象的时候,这个对象被构造函数初始化就有默认的初始值了。实例代码如下:

复制代码
class Program
    {
        static void Main(string[] args)
        {
           //没有办法调用默认的构造函初始化
            Point p;
            Console.WriteLine(p);

            //会调用默认的构造函数对的Point对象初始化
            Point p1 = new Point();
            Console.WriteLine(p1);
            Console.ReadKey();

        }
    }
    //定义结构
    struct Point
    {
        //定义时赋初始值,编译器会报错
        private int x;
    }
复制代码

编译的时候会报错:

 

 

 3)结构体不能使用自动属性

动属性的时候,反编译源代码,知道自动属性,会生成一个默认字段。而在结构的构造函数中需要对每一个字段赋值,但是编译器不知道这个字段的名字。所以,没有办法使用自动属性。

那么什么时候定义类,什么时候定义结构体呢?

首先我们都知道的是,栈的访问速度相对于堆是比较快的。但是栈的空间相对于堆来说是比较小的。

①当我们要表示一个轻量级的对象,就可以定义结构体,提高访问速度。

②根据传值的影响来选择,当要传递的引用就定义类,当要传递的是“拷贝”就定义结构体。

二,静态成员和实例成员的区别:

静态成员是需要通过static关键字来修饰的,而实例成员不用static关键字修饰。他们区别如下代码:

复制代码
class Program
    {
        static void Main(string[] args)
        {
            //静态成员属于类,可以直接通过“类名.静态成员”的方式访问
            Person.Run();

            //实例成员属于对象,需要通过“对象名.实例成员”来访问
            Person p = new Person();
            p.Sing();
        }
    }

    class Person
    {
        //静态成员变量
        private static int nAge;
        //实例成员变量
        private string strName;

        public static void Run()
        {
            Console.WriteLine("我会奔跑!");
        }

        public void Sing()
        {
            Console.WriteLine("我会唱歌");
        }
    }
复制代码

当类第一次被加载的时候(就是该类第一次被加载到内存当中),该类下面的所有静态的成员都会被加载。实例成员有多少对象,就会创建多少对象。

而静态成员只被加载到静态存储区,只被创建一次,且直到程序退出时才会被释放。

看下面的代码:

复制代码
class Program
    {
        static void Main(string[] args)
        {

            Person p = new Person();
            Person p1 = new Person();
            Person p2 = new Person();

        }
    }

    

    class Person
    {
        //静态成员变量
        private static int nAge;
        //实例成员变量
        private string strName;

        public static void Run()
        {
            Console.WriteLine("我会奔跑!");
        }

        public void Sing()
        {
            Console.WriteLine("我会唱歌");
        }
    }
复制代码

那么在内存中发生了什么呢?如下图:

由上面显然可知,定义静态的成员是可以影响程序的执行效率的。那么什么时候定义静态的成员变量呢?

①变量需要被共享的时候②方法需要被反复的调用的时候 

2)在静态方法中不能直接调用实例成员。

this和base关键字都不能在静态方法中使用。

②可以创建类的对象指明对象的成员在静态方法中操作

 

③在实例成员中肯定可以调用静态方法,因为这个时候静态成员肯定存在

静态成员和实例成员的对比:

①生命周期不一样

静态成员只有在程序结束时才会释放,而实例成员没有对象引用时就会释放

②内存中存储的位置不一样

静态成员存放在静态存储区,实例成员在托管堆中。

三,静态类

①静态类被static关键字修饰

 

②静态类中只能生命静态的成员变量,否则会报错(因为访问该实例成员的时候,类的对象可能还没有被创建)

③静态类中不能有实例的构造函数

 

④静态类不能被继承

会发现静态类的本质是一个抽象密封类,所以不能被继承和实例化。所以,静态类的构造函数,不能有访问修饰符

 

posted @   C#工控菜鸟  阅读(224)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示