解决方案 »

  1.   

    1. 不能那样写,会导致编译的时候CS0176错误。也就是不允许通过实例引用访问静态成员。不过如果是实例成员返回了自身,那是可以一直写下去的。返回自身是很有用的,比如一些method chain或者说fluent风格的语法,就需要返回this方便一连串的方法拼接。2. 静态方法只能访问静态成员,可以说是一种结构化实现,而实例方法可以访问实例成员,也就有了多态的可能。不过你要是不考虑继承,仅仅和自身的静态实例去比较,就没多少差别。一个就是那个实例占用了十几个字节的内存,另一个是静态构造方法如果产生异常,那么它不会被再次调用,也就是说这个类是用不了了,而实例构造没有这么大影响。不过这里需要注意,静态成员会在静态构造里面初始化,如果你在静态构造里面初始化了一个自身的实例,而实例构造方法还要依赖一些静态成员,那么就需要延迟实例构造。
      

  2.   

    abc.AA.AA.AA.AA.AA..abc是个对象, AA 是abc的属性, 属性后面还能跟属性?
      

  3.   

    实体类怎么可能调用static方法呢?
      

  4.   

    你的第二个问题,每一个类型都是一个单独的、不可实例的对象,然后根据这个类型对象可以实例化对象。例如a1类型是一个类型对象,相关的static字段、属性和static方法都是承载在(或者说作用在)类型对象上的。而其实例方法f1,只是承载在(或者说作用在)a1类型对象的实例化对象上。在.net程序中,不论有几百和还是几千个a1实例对象,系统都只允许有一个a1类型对象。每一个对象实例(我们把对象实例简称对象,而通常忽略类型对象)都是唯一标识的,并且每一个对象都有自己的类型,这是面向对象的几个基本特种中首先的两个特征。于是,从a1实例对象中,很自然地,即可以访问自身的f1方法,也可以访问a1类型对象上的 AA 属性。一个属性、一个方法,它或者属于某种对象实例的,或者属于类型对象的。对象实例更接近于自然的领域的对象模型。但是对象实例,都是有类型的,这个类型也是实实在在的“存在”,可以用代码访问上面的字段、属性、方法,声明的语法就是写static关键字。
      

  5.   

    在你的代码中,如果你写private readonly a1 @bb = new a1();
    这会在运行时产生栈溢出异常。但是这是运行时出的问题,并不妨碍编译器已经搞明白了你需要什么东西,并且给你正确地编译出了代码。所以在一个a1类型中有个属性引用一个a1类型的实例,或者有个属性引用在a1之“后”你才写上去的类型,这都不会影响编译器的全局理解能力,都可以编译具有可执行力的代码,代码的执行行为也是逻辑清晰的(只不过你需要放弃“抠字眼”的习惯,而看实际)。
      

  6.   


    语法只是给编译器看的,为了规范编译生成中间语言,在内存中没有语法.就是说语法编译器定的规矩,编译器在编译的时候会先检查你写的代码是不是合它的规定.之后编译器会编译成IL.CLR在遇到某个类的首次使用时会加载类所在的程序集到内存中.为每个类创建一个类的对象,这个类对象明确描述了该类的各种信息.其中,会为该类的静态的属性在栈空间单独创建一个静态存储区并在首次加载的时候初始化.在需要创建实例对象的时候就使用该类的类对象去创建一个实例对象并创建一个元数据表.在内存中类跟对象没有关系.
      

  7.   


    语法只是给编译器看的,为了规范编译生成中间语言,在内存中没有语法.就是说语法编译器定的规矩,编译器在编译的时候会先检查你写的代码是不是合它的规定.之后编译器会编译成IL.CLR在遇到某个类的首次使用时会加载类所在的程序集到内存中.为每个类创建一个类的对象,这个类对象明确描述了该类的各种信息.其中,会为该类的静态的属性在栈空间单独创建一个静态存储区并在首次加载的时候初始化.在需要创建实例对象的时候就使用该类的类对象去创建一个实例对象并创建一个元数据表.在内存中类跟对象没有关系.谢谢你的解答
    我想知道是,静态属性和静态方法等都在程序开始运行时,就在加载到内存中,比如说是1K(假设这个类只存在静态成员),那这种在类中声明一个自己的静态实例,这个实例是不是也占用1K的大小呢,另外,这种做法是否为了实现延迟加载
      

  8.   

    private static readonly a1 @aa = new a1();
    这很明显并不延迟加载,而是在初始化的时候就加载了
      

  9.   


    语法只是给编译器看的,为了规范编译生成中间语言,在内存中没有语法.就是说语法编译器定的规矩,编译器在编译的时候会先检查你写的代码是不是合它的规定.之后编译器会编译成IL.CLR在遇到某个类的首次使用时会加载类所在的程序集到内存中.为每个类创建一个类的对象,这个类对象明确描述了该类的各种信息.其中,会为该类的静态的属性在栈空间单独创建一个静态存储区并在首次加载的时候初始化.在需要创建实例对象的时候就使用该类的类对象去创建一个实例对象并创建一个元数据表.在内存中类跟对象没有关系.谢谢你的解答
    我想知道是,静态属性和静态方法等都在程序开始运行时,就在加载到内存中,比如说是1K(假设这个类只存在静态成员),那这种在类中声明一个自己的静态实例,这个实例是不是也占用1K的大小呢,另外,这种做法是否为了实现延迟加载
    静态属性和静态方法等并不是在程序开始运行时就加载到内存中的,当CLR使用到该类的时候,才会加载该类所在的程序集到内存中,静态类不能实例对象,整个类的属性和方法都在栈静态存储区.申明的引用类型的变量只是一个引用,存的是指向该引用类型的对象所在的栈空间地址.
      

  10.   


    谢谢你的解答。可是哥,我真没想想明白咋就被扣上了“抠字眼”的帽子,我真不是在“抠字眼",只是被这种写法给绕进去了。现在我是明白了,语法是语法,运行是运行的道理,但让我不解的是既然这样的语法在运行时会出错,那为什么还允许这样的语法存在。发这个帖子时我并没真正的将AA写成非静态属性来测试,现在测了,确实是通过编译但在运行时出错了,VS给出的错误如下:提示是”无限循环“或”无限递归“,这不就是嵌套的概念吗以前我在别人的代码中也见到过这样的写法,而且是非静态的自身实例。我们知道无论实例化对象或者是静态东东,都是要占用内存的,那静态的是程序一开始就加载到内存,实例对象是实例化时开辟内存,那么在类外面实例化时,这个类中自身的实例指针又是指到哪儿,静态的这个指针我想应该是指向自己所在的这块内存。还有就是,假设类中只存在静态成员,加载到内存是1K,那这种包含非静态成员,而声明自身静态实例的,是否也只占用1K的内存空间?若有言语过激之处,实在无意冒犯,望海涵,望仍继续指点迷津,谢谢
      

  11.   

    最基础的语法都不好学,一群人在那扯什么设计模式,还延迟加载,我也是醉了.我是看到了CSDN的.net社区的一群人有多逗,怪不得java社区的人经常嘲笑.这种社区以后坚决不来
      

  12.   


    谢谢你的解答,这种写法就是单例模式中所谓的“饿汉模式”。
    我想知道的是内存分配上有什么区别,哪种方法更有效率请看《clr via c#》
      

  13.   

    写成这样
    while(true){}
    也是一个合法的语法,只不过一运行程序就死掉了而已
    编译器还没智能到明白你到底想干啥,到底就是想让程序死掉,还是想让程序不死掉
    你必须自己调试,自己保证逻辑的正确
    编译器只能检测语法是否正确,逻辑是否正确它可不明白
      

  14.   

    编译器又不是人工智能AI
    即使它是人工智能,在没加入语言交流,仅靠分析你写的代码,它也不知道你到底想干啥鬼知道你是不是在测试当前内存和CPU到底能开多少线程,能支持多少次的递归
    造成堆栈溢出也是你自己的逻辑造成的,也可以说是硬件限制的
    如果内存无限大,即使无限递归了,说不定坚持24小时它还没报错呢,怎么说就不是正确的语法了