C#面试题(二)(包含答案) ------ GC/反射泛型

1.GC 机制

          垃圾收集,Garbage Collector(垃圾收集器,在不至于混淆的情况下也成为GC)以应用程序的root为基础,遍历应用程序在Heap上动态分配的所有对象,通过识别它们是否被引用来确定哪些对象是已经死亡的、哪些仍需要被使用。已经不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收。
          比较常见的算法有Reference Counting,Mark Sweep,Copy Collection等等

首先,GC并不是能释放所有的资源。它不能自动释放非托管资源。

第二,GC并不是实时性的,这将会造成系统性能上的瓶颈和不确定性。  

         托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源。

         非托管资源指的是.NET不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,例如文件,窗口,网络连接,数据库连接,画刷,图标等。这类资源,垃圾回收器在清理的时候会调用Object.Finalize()方法。默认情况下,方法是空的,对于非托管对象,需要在此方法中编写回收非托管资源的代码,以便垃圾回收器正确回收资源。   

          在.NET中,Object.Finalize()方法是无法重载的,编译器是根据类的析构函数来自动生成Object.Finalize()方法的,所以对于包含非托管资源的类,可以将释放非托管资源的代码放在析构函数。

   GC并不是实时性的,这会造成系统性能上的瓶颈和不确定性。所以有了IDisposable接口,IDisposable接口定义了Dispose方法,这个方法用来供程序员显式调用以释放非托管资源。使用using语句可以简化资源管理。

public class Foo : IDisposable
{
    private bool disposed = false;
    //既释放托管资源,又释放非托管资源
    public void Dispose()
    {
        Dispose(true);
        //将对象从垃圾回收器链表中移除,      
        //从而在垃圾回收器工作时,只回收托管资源,而不执行对象的析构函数
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //释放托管资源
            }
            // 释放非托管资源
            disposed = true;
        }
    }
    //析构函数不是人工调用,由垃圾回收器调用,用于释放非托管资源
    ~Foo()
    {
        Dispose(false);
    }
}
  using (Student stu = new Student() { StuID = 2 })
    {
        Console.WriteLine("释放之前》");
        Console.WriteLine(stu == null);
    }

  using 关键字保证在离开 using 作用域的时候一定会调用 Dispose 。所以,如果只是在局部使用了 IDisposable 变量,最好这样包起来,以防止内存泄漏。


System.GC 下的方法:

扫描二维码关注公众号,回复: 2710297 查看本文章

 GC.SuppressFinalize(this); //请求公共语言运行时不要调用指定对象的终结器。调用Dispose方法,销毁了对象,而GC并不知道,这个方法就是告诉GC,不需要在调用这些对象的Finalize()方法了,

 GC.GetTotalMemory(false); //检索当前认为要分配的字节数。 一个参数,指示此方法是否可以等待较短间隔再返回,以便系统回收垃圾和终结对象。

 GC.Collect();  //强制对所有代进行即时垃圾回收

   GC.AddMemoryPressure(); //通知运行时在安排垃圾回收时应考虑分配大量的非托管内存。

   GC.CancelFullGCNotification();  //取消注册垃圾回收通知。

    GC.CollectionCount();  //返回已经对对象的指定代进行的垃圾回收次数。

    GC.EndNoGCRegion();  //结束无 GC 区域延迟模式。

    GC.GetGeneration();  //返回对象的当前代数。

    GC.GetTotalMemory();  //检索当前认为的要分配的字节数

    GC.KeepAlive();             //引用指定对象,使其从当前例程开始到调用此方法的那一刻为止均不符合进行垃圾回收的条件。

    GC.RegisterForFullGCNotification ();   //指定当条件支持完整垃圾回收以及回收完成时,应引发垃圾回收通知。

    GC.RemoveMemoryPressure();  //通知运行时已释放非托管内存,在安排垃圾回收时不需要再考虑它。

    GC.ReRegisterForFinalize();  //请求系统调用指定对象的终结器,此前已为该对象调用 SuppressFinalize。

    GC.TryStartNoGCRegion();  //在关键路径执行期间尝试禁止垃圾回收。

    GC.WaitForFullGCApproach();   //返回已注册通知的状态,用于确定公共语言运行时是否即将引发完整、阻碍性垃圾回收。

    GC.WaitForFullGCComplete ();  //返回已注册通知的状态,用于确定公共语言运行时引发的完整、阻碍性垃圾回收是否已完成。

    GC.WaitForPendingFinalizers ();   //挂起当前线程,直到处理终结器队列的线程清空该队列为止。


                    C#IDisposable 接口&资源释放

2.CLR  IL  等概念

     1.Net平台上各种高级语言,如c#、VB、F#等编写的代码,
     2.首先会通过各自的解释器,解释成(MS)IL(Intermediate Language)(微软)(中间语言)组成的字节码,
     3.最后通过CLR(Common Language Runtime)(公共语言运行时)特定的JIT(实时编译器)编译成机器码。

3.反射 / 泛型

首先来了解type类:

 Type类的属性:
        Name 数据类型名
        FullName 数据类型的完全限定名(包括命名空间名)
        Namespace 定义数据类型的命名空间名
        IsAbstract 指示该类型是否是抽象类型
        IsArray   指示该类型是否是数组
        IsClass   指示该类型是否是类
        IsEnum   指示该类型是否是枚举
        IsInterface    指示该类型是否是接口
        IsPublic 指示该类型是否是公有的
        IsSealed 指示该类型是否是密封类
        IsValueType 指示该类型是否是值类型
    Type类的方法:
        GetConstructor(), GetConstructors():返回ConstructorInfo类型,用于取得该类的构造函数的信息
        GetEvent(), GetEvents():返回EventInfo类型,用于取得该类的事件的信息
        GetField(), GetFields():返回FieldInfo类型,用于取得该类的字段(成员变量)的信息
        GetInterface(), GetInterfaces():返回InterfaceInfo类型,用于取得该类实现的接口的信息
        GetMember(), GetMembers():返回MemberInfo类型,用于取得该类的所有成员的信息
        GetMethod(), GetMethods():返回MethodInfo类型,用于取得该类的方法的信息
        GetProperty(), GetProperties():返回PropertyInfo类型,用于取得该类的属性的信息
    可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其他类的Invoke()方法。 

反射的用途:

    (1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。   

    //通过程序集的名称反射
    Assembly ass = Assembly.Load("ClassLibrary831");
    Type t = ass.GetType("ClassLibrary831.NewClass");
    object o = Activator.CreateInstance(t, "grayworm", "http://hi.baidu.com/grayworm");
    MethodInfo mi = t.GetMethod("show");
    mi.Invoke(o, null);
   //通过DLL文件全名反射其中的所有类型
    Assembly assembly = Assembly.LoadFrom("xxx.dll的路径");
    Type[] aa = a.GetTypes();
    foreach(Type t in aa)
    {
        if(t.FullName == "a.b.c")
        {
            object o = Activator.CreateInstance(t);
        }
    }
    (2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 

    (3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。 

        Type t = T.GetType();
        ConstructorInfo[] ci = t.GetConstructors();    //获取类的所有构造函数,也可以传GetProperties参数
        foreach (ConstructorInfo c in ci) //遍历每一个构造函数
        {
            ParameterInfo[] ps = c.GetParameters();    //取出每个构造函数的所有参数
            foreach (ParameterInfo pi in ps)   //遍历并打印所该构造函数的所有参数
            {
                Console.Write(pi.ParameterType.ToString()+" "+pi.Name+",");
            }
            Console.WriteLine();
        }

           GetProperties(BindingFlags)说明:

Instance|Public:获取公共的的实例属性(非静态的)
Instance|NonPublic:获取非公共的的实例属性(非静态的)。(private/protect/internal)
Static|Public:获取公共的静态属性
Static|NonPublic:获取非公共的静态属性。(private/protect/internal)
Instance|Static|Public:获取公共的的实例或静态属性
Instance|Static|NonPublic:非获取公共的的实例或静态属性

          用构造函数动态生成对象:

        Type t = typeof(NewClassw);
        Type[] pt = new Type[2];
        pt[0] = typeof(string);
        pt[1] = typeof(string);
        //根据参数类型获取构造函数 
        ConstructorInfo ci = t.GetConstructor(pt); 
        //构造Object数组,作为构造函数的输入参数 
        object[] obj = new object[2]{"grayworm","hi.baidu.com/grayworm"};   
        //调用构造函数生成对象 
        object o = ci.Invoke(obj);    
        //调用生成的对象的方法测试是否对象生成成功 
        //((NewClassw)o).show();    

    用Activator生成对象,其中方法返回的对象就是对应的实例引用:

        Type t = typeof(NewClassw);
        //构造函数的参数 
        object[] obj = new object[2] { "grayworm", "hi.baidu.com/grayworm" };   
        //用Activator的CreateInstance静态方法,生成新对象 
        object o = Activator.CreateInstance(t,"grayworm","hi.baidu.com/grayworm"); 

     (4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。

        Type t = T.GetType();
        MethodInfo[] mis = t.GetMethods();
        foreach (MethodInfo mi in mis)
        {
            MethodInfo mi1 = t.GetMethod(mi.Name, BindingFlags.NonPublic | BindingFlags.Instance);
            MethodInfo mi2 = mi.MakeGenericMethod(new Type[] { typeof(string) });
            mi2.Invoke(p, new object[] { "abcdefg" });
            Console.WriteLine(mi.ReturnType+" "+mi.Name);
        }

    (5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。

        Type t = nc.GetType();
        FieldInfo[] fis = t.GetFields();
        foreach (FieldInfo fi in fis)
        {
            Console.WriteLine(fi.Name);
        }

    (6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。 

                Type t = nc.GetType();
                EventInfo[] events = t .GetEvents();
                 // 输出事件信息
                 foreach (EventInfo ev in events)
                 {
                     Console.WriteLine("  事件名:{0},事件类型:{1}", ev.Name, ev.EventHandlerType.Name);
                 }

    (7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。

        Type t = nc.GetType();
        PropertyInfo[] pis = t.GetProperties();
        foreach(PropertyInfo pi in pis)
        {
            Console.WriteLine(pi.Name);
            Debug.log (T.GetType().GetProperty(p.Name).GetValue(T, null))
        }

如果要访问引用变量,可以使用特定的名字来访问:

            var list = T.GetType().GetProperty("dictionaryName").GetValue(T, null);
            foreach (object o in (list as IEnumerable))
            {
                var itemKey = o.GetType().GetProperty("Key").GetValue(o, null);
                Console.WriteLine(itemKey);
 
                var itemValue = o.GetType().GetProperty("Value").GetValue(o, null);
                foreach (object subItem in (itemValue as IEnumerable))
                    Console.WriteLine(subItem);
            }

    (8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。    

        Type t = nc.GetType();
        MethodInfo[] mis = t.GetMethods();
        foreach (MethodInfo mi in mis)
        {
            ParameterInfo[] ps = mi.GetParameters();    //取出每个构造函数的所有参数
            foreach (ParameterInfo pi in ps)   //遍历并打印所该构造函数的所有参数
            {
                Console.Write(pi.ParameterType.ToString()+" "+pi.Name+",");
            }
       }
      参考:  1. 程序集与反射技术(C#)
                2. 详解C#中的反射 


  

猜你喜欢

转载自blog.csdn.net/dengshunhao/article/details/81033250