从入门到入土-基础篇-1

c#基础面试篇

面试的时候总是会问 会了感觉也就那样但是不会面试又问,但总归懂的原理档次才能上升才能写出来更好的程序和逻辑。

你好! 欢迎来到唯快不破的博客,今天遇到了一些又高兴又不高兴的事情,曾经两家在一个公司的同事问我有没有要换工作的.net 程序员,我扫了一圈也没有,后来想想他们公司是大厂,那我要不要试试呢?除了公司太远没有太大的毛病啊,最近一直在上架构班的课,想着上完了在去面试啥的,可是他们又只有两个月的招聘时间,想想还是去试试吧,但是想到面试的东西 好久都没有碰了,基础也弱化了,他甩给我一个url打开一看是他收藏的一些.net资料那好二话不说 啃一啃吧,啃的时候啊 怕啃完了忘了啊所以就 博客来一波吧,顺便给自己和码友们分享和记录一些。

=值类型和引用类型=

你说下面的代码他能输出啥,基础弱的容易出Bug 你还真别不信所以面试的时候面基础也是有道理的

User u1 = new User();
u1.Age = 0;
User u2 = u1;
u2.Age = 100;
Console.WriteLine("u1.Age=" + u1.Age); 
Console.WriteLine("u2.Age=" + u2.Age); 

答案当然是最后给出了 要不你都看见了还测试啥;

直接说值类型和引用类型,分3个维度:

  1. 内存存储

    值类型存储在栈(Stack )上,引用类型在堆(GC Heap)上
    

Stack 栈:线程栈,由操作系统管理,存放值类型、引用类型变量(就是引用对象在托管堆上的地址)。栈是基于线程的,也就是说一个线程会包含一个线程栈,线程栈中的值类型在对象作用域结束后会被清理,效率很高。
GC Heap托管堆:进程初始化后在进程地址空间上划分的内存空间,存储.NET运行过程中的对象,所有的引用类型都分配在托管堆上,托管堆上分配的对象是由GC来管理和释放的。托管堆是基于进程的,当然托管堆内部还有其他更为复杂的结构,有兴趣的可以深入了解。
值类型变量声明后,不管是否已经赋值,编译器为其分配内存。
声明一个引用类时,只在栈中分配内存,用于存放地址,而并没有为其分配堆上的内存空间。

2、对象的传递
将值类型的变量赋值给另一个变量(或者作为参数传递),会执行一次值复制。将引用类型的变量赋值给另一个引用类型的变量,它复制的值是引用对象的内存地址,因此赋值后就会多个变量指向同一个引用对象实例。理解这一点非常重要,到这就可以知道上面的题目的答案是 都是100;如果都是int则第一个是0第二个是100;

  1. 作为参数传递
static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");



            //User u1 = new User();
            //u1.Age = 0;
            //User u2 = u1;
            //u2.Age = 100;
            //Console.WriteLine("u1.Age=" + u1.Age); 
            //Console.WriteLine("u2.Age=" + u2.Age);

            int a = 10;
            int b = dotest(a);
            Console.WriteLine(b);
            Console.WriteLine(a);

            User u = new User();
            u.Age = 1; 
            dostringtest(ref u);
            Console.WriteLine(u.Age);
            Console.ReadLine();
        }
        private static int dotest(int a)
        {
            a *= 2;
            return a;
        }

        private static void dostringtest(ref User user)
        {
            user.Age *= 2; 
        }

对于值类型(int a) :传递的是变量a的值拷贝副本,因此原本的a值并没有改变。
对于引用类型(User user) :传递的是变量user的引用地址(User对象实例的内存地址)拷贝副本,因此他们操作都是同一个User对象实例。
//分别输出:a=10 user.Age=2

看看我们平常用的:从入门到入土-基础篇-1

从入门到入土-基础篇-1

  1. 值类型和引用类型的区别?
    值类型包括简单类型、结构体类型和枚举类型,引用类型包括自定义类、数组、接口、委托等。

1、赋值方式:将一个值类型变量赋给另一个值类型变量时,将复制包含的值。这与引用类型变量的赋值不同,引用类型变量的赋值只复制对象的引用(即内存地址,类似C++中的指针),而不复制对象本身。
2、继承:值类型不可能派生出新的类型,所有的值类型均隐式派生自 System.ValueType。但与引用类型相同的是,结构也可以实现接口。
3、null:与引用类型不同,值类型不可能包含 null 值。然而,可空类型允许将 null 赋给值类型(他其实只是一种语法形式,在clr底层做了特殊处理)。
4、每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值,值类型初始会默认为0,引用类型默认为null。
5、值类型存储在栈中,引用类型存储在托管堆中。
2. 结构和类的区别?
结构体是值类型,类是引用类型,主要区别如题1。其他的区别:

结构不支持无惨构造函数,不支持析构函数,并且不能有protected修饰;
结构常用于数据存储,类class多用于行为;
class需要用new关键字实例化对象,struct可以不适用new关键字;
class可以为抽象类,struct不支持抽象;
3. delegate是引用类型还是值类型?enum、int[]和string呢?
enum枚举是值类型,其他都是引用类型。

  1. 堆和栈的区别?
    线程堆栈:简称栈 Stack
    托管堆: 简称堆 Heap
    值类型大多分配在栈上,引用类型都分配在堆上;
    栈由操作系统管理,栈上的变量在其作用域完成后就被释放,效率较高,但空间有限。堆受CLR的GC控制;
    栈是基于线程的,每个线程都有自己的线程栈,初始大小为1M。堆是基于进程的,一个进程分配一个堆,堆的大小由GC根据运行情况动态控制;
    6.“结构”对象可能分配在堆上吗?什么情况下会发生,有什么需要注意的吗?
    结构是值类型,有两种情况会分配在对上面:

结构作为class的一个字段或属性,会随class一起分配在堆上面;
装箱后会在堆中存储,尽量避免值类型的装箱,值类型的拆箱和装箱都有性能损失,下一篇会重点关注;
7. 理解参数按值传递?以及按引用传递?
按值传递:对于值类型传递的它的值拷贝副本,而引用类型传递的是引用变量的内存地址,他们还是指向的同一个对象。
按引用传递:通过关键字out和ref传递参数的内存地址,值类型和引用类型的效果是相同的。
8. out 和 ref的区别与相同点?
out 和 ref都指示编译器传递参数地址,在行为上是相同的;
他们的使用机制稍有不同,ref要求参数在使用之前要显式初始化,out要在方法内部初始化;
out 和 ref不可以重载,就是不能定义Method(ref int a)和Method(out int a)这样的重载,从编译角度看,二者的实质是相同的,只是使用时有区别;
9. C#支持哪几个预定义的值类型?C#支持哪些预定义的引用类型?
值类型:整数、浮点数、字符、bool和decimal

引用类型:Object,String

  1. 有几种方法可以判定值类型和引用类型?
    简单来说,继承自System.ValueType的是值类型,反之是引用类型。

  2. 说说值类型和引用类型的生命周期?
    值类型在作用域结束后释放。

引用类型由GC垃圾回收期回收。这个答案可能太简单了,更详细的答案在后面的文章会说到。

  1. 如果结构体中定义引用类型,对象在内存中是如何存储的?例如下面结构体中的class类 User对象是存储在栈上,还是堆上?
    public struct MyStruct
    {
    public int Index;
    public User User;
    }
    MyStruct存储在栈中,其字段User的实例存储在堆中,MyStruct.User字段存储指向User对象的内存地址。

本文主要摘抄自:http://www.cnblogs.com/anding

上一篇:sqlalchemy中的back_populates和backref


下一篇:ORM框架入门实例3