2009-01-01 22:50:16 duan2564 阅读数 32
  • C#系列课程面向对象篇

    这个是继《C#系列课程之基础知识入门篇》的篇,主要讲解的是C#中面向对象的有关知识,主要有类,接口,继承,多态,构造函数,析构函数,密封类,属性,抽象,结构体,枚举,静态类,部分类等等有关面向对象的专业知识。

    1542 人正在学习 去看看 徐新帅

今天看到了一个帖子题目说是"C#静态变量的诡异与恶心 "

我也说说我的看法,看下面的C#代码

   1. using System;  
   2.   
   3. namespace StaticTest  
   4. {  
   5.     class A  
   6.     {  
   7.         public static int X;  
   8.         static A()  
   9.         {  
  10.             X = B.Y + 1;  
  11.         }  
  12.     }  
  13.     class B  
  14.     {  
  15.         public static int Y = A.X + 1;  
  16.         static B()  
  17.         {  
  18.         }  
  19.         static void Main()  
  20.         {  
  21.             Console.WriteLine("X={0}, Y={1}", A.X, B.Y);  
  22.         }  
  23.     }  
  24. }  

 打印结果为X= 1 , Y= 2

第二个例子,java代码

   1. class StaticTest  
   2. {  
   3.     public static void main(String[] args){  
   4.         System.out.println(Integer.toString(A.X) +" "+Integer.toString(B.Y));  
   5.     }  
   6. }  
   7.   
   8. class A  
   9. {  
  10.     static int X = B.Y + 1;  
  11. }  
  12.   
  13. class B  
  14. {  
  15.     static int Y = A.X + 1;  
  16. }  
打印的结果为 2 1
结果看上去挺诡异的,其实还是需要分析一下
C#与java差不多,不分开讲
对于第一个例子,
1 在运行main之前,所有的变量进行默认初始化,X=0,Y=0
2 为了运行main方法,需要对类B进行静态初始化
3 B静态初始化,需要初始化静态变量Y
4 Y的初始化需要用到A的变量X,需要初始化类A
5 A的初始化时,又需要用到了Y变量,而此时类B早已经开始初始化,故不会再对B初始化,避免循环
6 直接取Y=0,得到X=1
7 然后返回后Y再被初始化为2
对于第二个例子
1 在运行main之前,所有的变量进行默认初始化,X=0,Y=0
2 由于需要调用A.X,故需要对A进行静态初始化
3 A中使用Y,对B进行初始化
4 B中又用到X,但由于A已经开始初始化,故不循环,直接取X=0,得到Y=1
5 然后得到X=2
 
2008-04-15 11:25:00 hfzsjz 阅读数 5303
  • C#系列课程面向对象篇

    这个是继《C#系列课程之基础知识入门篇》的篇,主要讲解的是C#中面向对象的有关知识,主要有类,接口,继承,多态,构造函数,析构函数,密封类,属性,抽象,结构体,枚举,静态类,部分类等等有关面向对象的专业知识。

    1542 人正在学习 去看看 徐新帅

C#中是没有所谓的全局变量的.要构造出类的属性作为全局变量
例如:新建类GlobalParams
可以在类中这样写:
public static string user = ""; //定义变量
public GlobalParams ()
{
user ="abcd";//赋值构造
}
public string User
{
get
{
return user ;
}
set
{
user =value;
}

这样就可以其他窗体访问此User
MessageBox.Show (GlobalParams .User); //直接访问. 显示.结果:"abcd"

GlobalParams frm=new GlobalParams ();
frm.User="efg"; //修改该静态变量的值

MessageBox.Show (GlobalParams .User); //直接访问. 显示.结果:"efg"

2016-06-10 12:05:15 MsdnWoo 阅读数 630
  • C#系列课程面向对象篇

    这个是继《C#系列课程之基础知识入门篇》的篇,主要讲解的是C#中面向对象的有关知识,主要有类,接口,继承,多态,构造函数,析构函数,密封类,属性,抽象,结构体,枚举,静态类,部分类等等有关面向对象的专业知识。

    1542 人正在学习 去看看 徐新帅

类的静态字段变量初始值设定项对应于一个赋值序列,这些赋值按照它们在相关的类声明中出现的文本顺序执行。

如果类中存在静态构造函数则静态字段初始值设定项的执行在该静态构造函数即将执行前发生。

否则,静态字段初始值设定项在第一次使用该类的静态字段之前先被执行,但实际执行时间依赖于具体的实现。在以下示例中:

using System;  
class Test  
{  
    static void Main() {  
       Console.WriteLine("{0} {1}",B.Y, A.X);  
    }  
    public static int F(string s) {  
       Console.WriteLine(s);  
       return 1;  
    }  
}  
class A  
{  
    public static int X= Test.F("Init A");  
}  
class B  
{  
    public static int Y= Test.F("Init B");  
} 

或者产生如下输出:
Init A
Init B
1 1
或者产生如下输出:
Init B
Init A
1 1
这是因为 X 的初始值设定项和 Y的初始值设定项的执行顺序无法预先确定,上述两种顺序都有可能发生;唯一能够确定的是:它们一定会在对那些字段的引用之前发生。

但是下面的示例:

using System;  
class Test  
{  
    static void Main() {  
        Console.WriteLine("{0} {1}",B.Y, A.X);  
    }  
    public static int F(string s) {  
       Console.WriteLine(s);  
      return 1;  
    }  
}  
class A  
{  
    static A() {}  
    public static int X= Test.F("Init A");  
}  
class B  
{  
    static B() {}  
    public static int Y= Test.F("Init B");  
} 
所产生的输出必然是:
Init B
Init A
1 1

 这是因为关于何时执行静态构造函数的规则规定

静态构造函数用于初始化任何 静态 数据,或用于执行仅需执行一次的特定操作。 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数。

:B的静态构造函数(以及B的静态字段初始值设定项)必须在A的静态构造函数和字段初始值设定项之前运行。


2014-11-05 15:11:00 weixin_34177064 阅读数 40
  • C#系列课程面向对象篇

    这个是继《C#系列课程之基础知识入门篇》的篇,主要讲解的是C#中面向对象的有关知识,主要有类,接口,继承,多态,构造函数,析构函数,密封类,属性,抽象,结构体,枚举,静态类,部分类等等有关面向对象的专业知识。

    1542 人正在学习 去看看 徐新帅

使用 static 修饰符声明属于类型本身而不是属于特定对象的静态成员static修饰符可用于类、字段、方法、属性、运算符、事件和构造函数,但不能用于索引器、析构函数或类以外的类型

 

静态全局变量

定义:在全局变量前,加上关键字 static 该变量就被定义成为了一个静态全局变量。

特点:   A、该变量在全局数据区分配内存。   B、初始化:如果不显式初始化,那么将被隐式初始化为0。

 

静态局部变量

定义:在局部变量前加上static关键字时,就定义了静态局部变量。

特点:   A、该变量在全局数据区分配内存。   B、初始化:如果不显式初始化,那么将被隐式初始化为0。   C、它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或 语句块结束时,其作用域随之结束。

静态数据成员
特点:   A、内存分配:在程序的全局数据区分配。   B、初始化和定义:     a、静态数据成员定义时要分配空间,所以不能在类声明中定义。     b、为了避免在多个使用该类的源文件中,对其重复定义,所在,不能在类的头文件中     定义。     c、静态数据成员因为程序一开始运行就必需存在,所以其初始化的最佳位置在类的内部实现。   C、特点     a、对相于 public,protected,private 关键字的影响它和普通数据成员一样,     b、因为其空间在全局数据区分配,属于所有本类的对象共享,所以,它不属于特定的类对象,在没产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它。
  D、访问形式     a、 类对象名.静态数据成员名

        E、静态数据成员,主要用在类的所有实例都拥有的属性上。比如,对于一个存款类,帐号相对   于每个实例都是不同的,但每个实例的利息是相同的。所以,应该把利息设为存款类的静态数据成员。这有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局区的内存,所以节省存贮空间。第二,一旦利息需要改变时,只要改变一次,则所有存款类对象的利息全改变过来了,因为它们实际上是共用一个东西。  

静态成员函数
特点:   A、静态成员函数与类相联系,不与类的对象相联系。   B、静态成员函数不能访问非静态数据成员。原因很简单,非静态数据成员属于特定的类实例。
作用:   主要用于对静态数据成员的操作。

调用形式:   A、类对象名.静态成员函数名()

 

static静态变量的实例与分析

 实例

 
C# 代码   复制
 using System;
namespace teststatic
{
    class class1
{
        static int i = getNum();
        int j = getNum();
        static int num = 1;
        static int getNum()
{
            return num;
        }
        static void Main(string[] args)
{
            Console.WriteLine("i={0}",i);
            Console.WriteLine("j={0}", new class1().j);
            Console.Read();
        }
    }
}

 

现在分析上面的代码

Console.WriteLine(string.Format("i={0}",i)); 这里i是static变量,而且类class1是第一次被引 用,要先为class1里面所有的static变量分配内存。尽管现在有超线程技术,但是指令在逻辑还是一条一条的按顺序执行的,所以 先为static int i分配内存,并且在该内存中保持int的缺省值0,接着再为static int num 变量分配内存,值当然也为0。

然后执行第二步,为变量赋值:先为static int i变量赋值,i=getNum(),看getNum里面的代码,就是return num,这个时候num的值是0,于是i就为0了。然后对变量num赋值,num=1;这行代码执行后,num就为1了。

所以最后的结果为:

 i=0 j=1

2013-04-27 13:58:58 theoldsod2000 阅读数 845
  • C#系列课程面向对象篇

    这个是继《C#系列课程之基础知识入门篇》的篇,主要讲解的是C#中面向对象的有关知识,主要有类,接口,继承,多态,构造函数,析构函数,密封类,属性,抽象,结构体,枚举,静态类,部分类等等有关面向对象的专业知识。

    1542 人正在学习 去看看 徐新帅

曾经以为,多线程可以访问静态变量,来实现多线程之间数据的共享。

事实上,虽然多线程可以访问静态变量,但是,会有延迟,可能访问的并不是最新的值。

要想在多个线程之间共享数据,并能及时访问到最新值,需要用Violate关键字。

以下是关于Volatile关键字的说明

volatile 关键字指示一个字段可以由多个同时执行的线程修改。声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。这样可以确保该字段在任何时间呈现的都是最新的值。

volatile 修饰符通常用于由多个线程访问但不使用 lock 语句对访问进行序列化的字段。



C# 断点不赋值问题

阅读数 127

没有更多推荐了,返回首页