大话C#语言——高级教程总结

版权声明:文章均是博主原创,如需转载,请在文章开头注明出处和署名! https://blog.csdn.net/shirln/article/details/85701100

推荐阅读:

特性

       用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。

Net 框架提供了三种预定义特性:

AttributeUsage
Conditional
Obsolete

反射

       反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
       程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。

反射(Reflection)有下列用途:

它允许在运行时查看特性(attribute)信息。
它允许审查集合中的各种类型,以及实例化这些类型。
它允许延迟绑定的方法和属性(property)。
它允许在运行时创建新类型,然后使用这些类型执行一些任务。

属性

       使用 访问器(accessors) 让私有域的值可被读写或操作。例如:有一个名为 Student 的类,带有 age私有域。我们不能在类的范围以外直接访问这些域,但是我们可以拥有访问这些私有域的属性。
代码实现如下:

using System;
namespace 属性
{
   class Student
   {
      private int age = 0;
      
      // 声明类型为 int 的 Age 属性
      public int Age
      {
         get
         {
            return age;
         }
         set
         {
            age = value;
         }
      }
    }
    
    class ExampleDemo
    {
      public static void Main()
      {
         // 创建一个新的 Student 对象
         Student s = new Student();
         s.Age = 9;         //9
         // 增加年龄
         s.Age += 1;         //10
         Console.ReadKey();
       }
   }
}

索引器

       允许一个对象可以像数组一样被索引。当为类定义一个索引器时,该类的行为就会像一个虚拟数组(virtual array) 一样。可以使用数组访问运算符 [ ] 来访问该类的实例。
格式如下:

//索引器定义的时候带有 this 关键字,它指向对象实例
element-type this[int index] 
{
   // get 访问器
   get 
   {
      // 返回 index 指定的值
   }

   // set 访问器
   set 
   {
      // 设置 index 指定的值 
   }
}

下面举个例子来看看索引器如何使用:

using System;
namespace 索引器
{
   class IndexedNames
   {
      private string[] namelist = new string[size];
      static public int size = 10;
      //初始化每个元素的值
      public IndexedNames()
      {
         for (int i = 0; i < size; i++)
         namelist[i] = "N. A.";
      }
      public string this[int index]
      {
      //取值,输出时用到
         get
         {
            string tmp;

            if( index >= 0 && index <= size-1 )
            {
               tmp = namelist[index];
            }
            else
            {
               tmp = "";
            }

            return ( tmp );
         }
         //设置值,重置值得时候使用
         set
         {
            if( index >= 0 && index <= size-1 )
            {
               namelist[index] = value;
            }
         }
      }

      static void Main(string[] args)
      {
         IndexedNames names = new IndexedNames();
         names[0] = "被重置后的值";
         for ( int i = 0; i < IndexedNames.size; i++ )
         {
            Console.WriteLine(names[i]);
         }
         Console.ReadKey();
      }
   }
}

上面代码在这里就不做过多的解释了,注释已经在代码中标注。

委托

       C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。派生自 System.Delegate 类。
格式:

[访问修饰符] delegate <return type> <delegate-name> <parameter list>

例如:

public delegate int MyDelegate (string s);

使用方法:

using System;

delegate int NumberChanger(int n);
namespace 委托
{
   class TestDelegate
   {
      static int num = 10;
      public static int AddNum(int p)
      {
         num += p;
         return num;
      }
      public static int getNum()
      {
         return num;
      }

      static void Main(string[] args)
      {
         // 创建委托实例
         NumberChanger nc1 = new NumberChanger(AddNum);
         // 使用委托对象调用方法
         nc1(25);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

委托的多播:委托对象可使用 “+” 运算符进行合并。只有相同类型的委托可被合并。
例如:

using System;

delegate int NumberChanger(int n);
namespace DelegateAppl
{
   class TestDelegate
   {
      static int num = 10;
      public static int AddNum(int p)
      {
         num += p;
         return num;
      }

      public static int MultNum(int q)
      {
         num *= q;
         return num;
      }
      public static int getNum()
      {
         return num;
      }

      static void Main(string[] args)
      {
         // 创建委托实例
         NumberChanger nc;
         NumberChanger nc1 = new NumberChanger(AddNum);
         NumberChanger nc2 = new NumberChanger(MultNum);
         nc = nc1;         //15
         nc += nc2;        //15*5=75
         // 调用多播
         nc(5);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

下面再举一个委托多播实例:例如小明叫小张买完车票,之后接着又让他带张电影票


// 小张类
public class MrZhang
    {
    // 其实买车票的悲情人物是小张
    public static void BuyTicket()
    {
            Console.WriteLine("NND,每次都让我去买票,鸡人呀!");
    }

    public static void BuyMovieTicket()
    {
        Console.WriteLine("我去,自己泡妞,还要让我带电影票!");
    }
}

//小明类
class MrMing
{
    // 声明一个委托,其实就是个“命令”
    public delegate void BugTicketEventHandler();

    public static void Main(string[] args)
    {
        // 这里就是具体阐述这个命令是干什么的,本例是MrZhang.BuyTicket“小张买车票”
        BugTicketEventHandler myDelegate = new BugTicketEventHandler(MrZhang.BuyTicket);

        myDelegate += MrZhang.BuyMovieTicket;
        // 这时候委托被附上了具体的方法
        myDelegate();
        Console.ReadKey();
    }
}

事件

       事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些出现,如系统生成的通知。事件使用 发布-订阅(publisher-subscriber) 模型。包含事件的类用于发布事件。这被称为 发布器(publisher) 类。其他接受该事件的类被称为 订阅器(subscriber) 类。
       发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。

       订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。

       通过事件使用委托:在类的内部声明事件,首先必须声明该事件的委托类型。然后,声明事件本身,使用 event 关键字。

例如:声明一个myDelegate委托,然后声明一个BoilerEventLog事件

//声明委托
public delegate void myDelegate();

// 基于上面的委托定义事件
public event BoilerLogHandler BoilerEventLog;

例如:在命名空间“通过事件使用委托”中,创建EventTest类作为发布器,并声明myDelegate委托和ChangeNum事件;创建subscribEvent类作为订阅器类;创建MainClass类,注册事件。


using System;
namespace 通过事件使用委托
{

  /***********发布器类***********/
  public class EventTest
  {
    private int value;
	//委托
    public delegate void myDelegate();
	//事件
    public event myDelegate  ChangeNum;
    
    //构造函数
    public EventTest()
    {
      int n = 5;
      SetValue( n );
    }
    
    protected void OnNumChanged()
    {
      if ( ChangeNum != null )
      {
      	//有事件
        ChangeNum(); /* 事件被触发 */
      }else {
      	//没有事件
        Console.WriteLine( "event not fire" );
        Console.ReadKey(); /* 回车继续 */
      }
    }
	//设置值,并触发事件
    public void SetValue( int n )
    {
      if ( value != n )
      {
        value = n;
        OnNumChanged();
      }else{
	  Console.WriteLine( "值相等" );
      Console.ReadKey(); /* 回车继续 */}
    }
  }


  /***********订阅器类***********/

  public class subscribEvent
  {
    public void printf()
    {
      Console.WriteLine( "event fire" );
      Console.ReadKey(); /* 回车继续 */
    }
  }

  /***********触发***********/
  public class MainClass
  {
    public static void Main()
    {
      EventTest e = new EventTest(); /* 实例化对象,第一次没有触发事件(事件为空) */
      subscribEvent v = new subscribEvent(); /* 实例化订阅器 */
      e.ChangeNum += new EventTest.myDelegate( v.printf ); /* 注册事件 */
      e.SetValue( 7 );
      e.SetValue( 10 );
    }
  }
}

集合

       在 C# 中,集合继承自System.Collection;在 C# 中,Object 类是所有数据类型的基类

1.动态数组(ArrayList):可以替代一个数组。与数组不同的是,可以使用索引在指定的位置添加和移除。

ArrayList al = new ArrayList();
al.Add(45);

2.哈希表(Hashtable)存储:键/值对,使用键来访问集合中的元素。

Hashtable ht = new Hashtable();
ht.Add("001", "小木游戏");

3.排序列表(SortedList):集合中的各项总是按键值排序排序,是数组和哈希表的组合,存储键/值对,使用键和索引来访问集合中的元素。如果使用索引访问各项,则它是一个动态数组(ArrayList),如果使用键访问各项,则它是一个哈希表(Hashtable)。

SortedList sl = new SortedList();
sl.Add("001", "小木游戏");
sl.Add("001", "小木子");
Console.WriteLine( sl[0]);//小木游戏

4.堆栈(Stack):后进先出

Stack st = new Stack();
st.Push('小木');
st.Push('游戏');
st.Pop();//游戏
st.Pop();//小木

5.队列(Queue):先进先出

Queue q = new Queue();
q.Enqueue('小木');
q.Enqueue('游戏');
char ch1 = (char)q.Dequeue();//小木
char ch2 = (char)q.Dequeue();//游戏

6.点阵列(BitArray):使用布尔值来表示,其中 true 表示位是开启的(1),false 表示位是关闭的(0)。当需要存储位,但是事先不知道位数时,则使用点阵列

// 创建两1个大小为 8 的点阵列
BitArray ba1 = new BitArray(8);
 byte[] a = { 60 };
 for (int i = 0; i < ba1.Count; i++)
 {
      Console.Write("{0, -6} ", ba1[i]);//False False True True True True False False
 }

上面输出结果为将60的二进制数,转换成对应的布尔值。

泛型

       在封装公共组件的时候,很多时候我们的类/方法不需要关注调用者传递的实体是"什么",这个时候就可以使用泛型。
泛型方法:

//交换函数
 static void Swap<T>(ref T lhs, ref T rhs)
{
     T temp;
     temp = lhs;
     lhs = rhs;
     rhs = temp;
}

static void Main(string[] args)
{
     int a = 10;
     int b = 20;
     char c = 'I';
     char  d = 'V';
     // 调用 swap
     Swap<int>(ref a, ref b);
     Swap<char>(ref c, ref d);
     Console.ReadKey();
}

泛型委托:

delegate T NumberChanger<T>(T n);

 // 创建委托实例
NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);

匿名方法

匿名方法是通过使用 delegate 关键字创建委托实例来声明的
例如:

delegate void NumberChanger(int n);
...
NumberChanger nc = delegate(int x)
{
    Console.WriteLine("Anonymous Method: {0}", x);
};

下面举个例子,使用两种方法创建委托:


using System;

delegate void NumberChanger(int n);
namespace DelegateAppl
{
    class TestDelegate
    {
        static int num = 10;
        public static void AddNum(int p)
        {
            num += p;
            Console.WriteLine("Named Method: {0}", num);
        }

        static void Main(string[] args)
        {
			///////////////方法一
            // 使用匿名方法创建委托实例
            NumberChanger nc = delegate(int x)
            {
               Console.WriteLine("Anonymous Method: {0}", x);
            };
            // 使用匿名方法调用委托
            nc(10);
			
			//////////////方法二
            // 使用命名方法实例化委托
            nc =  new NumberChanger(AddNum);
            // 使用命名方法调用委托
            nc(5);
            Console.ReadKey();
        }
    }
}

不安全代码

       不安全代码或非托管代码是指使用了指针变量的代码块。当一个代码块使用 unsafe 修饰符标记时,C# 允许在函数中使用指针变量
例如:在函数返回类型前加上关键字unsafe ,函数中便可以使用指针。

public unsafe void swap(int* p, int *q)
{
    int temp = *p;
    *p = *q;
    *q = temp;
}

多线程

       线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。为了同时执行多个任务,它可以被划分为更小的线程。
       线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。

线程生命周期中的各种状态:

1.未启动状态:当线程实例被创建但 Start 方法未被调用时的状况。
2.就绪状态:当线程准备好运行并等待 CPU 周期时的状况。
3.不可运行状态:下面的几种情况下线程是不可运行的:
已经调用 Sleep 方法
已经调用 Wait 方法
通过 I/O 操作阻塞
4.死亡状态:当线程已完成执行或已中止时的状况。

       进程中第一个被执行的线程称为主线程。当 C# 程序开始执行时,主线程自动创建。使用 Thread 类的 CurrentThread 属性访问线程。
1.创建线程用Thread :

Thread childThread = new Thread(“主线程名”);

注意:这种方法是创建子线程,因为主线程在程序开始时自动被创建
2.暂停线程用 sleep() 方法:

Thread.Sleep(暂停时间);

3.销毁线程用Abort()方法:

线程名.Abort();

猜你喜欢

转载自blog.csdn.net/shirln/article/details/85701100