首页 > 代码库 > C#基础

C#基础

笔记来自《C#图解教程》

每个.cs文件至少需要包含一个和文件名相同的类

析构函数:执行在类的实例被销毁之前需要的清理或释放非托管资料的行为。
每个类只能有一个析构函数;
不能带参数;
不能带访问修饰符。

虚方法/覆写方法(需要在派生类中重写基类的某些方法时)
virtual/override

访问修饰符:
public完全公开
private类内部(默认)
protected同一名字空间内的派生类可以访问
internal同一名字空间内的任何地方可以访问
protected internal或

抽象成员:abstract
不能virtual abstract
抽象的实现必须override

密封类(sealed):只能用作独立的类,不能被用作基类。

静态类:所有成员都标记static;不能继承,不能创建实例;

扩展方法:public static double Average(this MyData.md)

外部方法:在声明中没有实现的,其实现往往是用C#之外的语言编写的。
public static extern int func(int size, stringBuilder buf);

字符串:规格/逐字(以@为前缀)

左移相当于乘2的n次方;右移相当于乘2的-n次方;

用户自定义类型转换:
隐式转换:implicit
显式转换:explicit

运算符重载:
public static LimitedInt operator +(LimitedInt x, double y){}

typeof运算符:
Type t = typeof(SomeClass);
GetType/ToString/Equals/GetHashCode

数字在C#中没有布尔意义。

using别名指令:
using Syst = System;
using sc = System.Console;

catch子句:
catch{}
catch(Type){}
catch(Type instID){}

抛出异常:throw ExceptionObject;


结构

类是引用类型而结构是值类型;

结构是隐式密封的,不能被派生;
结构复制,从一个结构中把值复制到另一个结构,复制类变量时只有引用被复制。
预定义的无参数构造函数对每个结构都存在,而且不能删除或重定义方法。
不能new创建struct,不能使用数据成员的值直到显式设置它。
字段初始化是不允许的。
分配结构比创建类的实例需要更少的消耗。

枚举

enum TrafficLight : long
{
     Green = 10,
     Yellow, //值为11
     Red //值为12
}
值类型:只有一种类型的成员,命名的整数值常量;
每个枚举类型都是一个底层整数类型,默认为int。

数组

(引用类型):一旦创建,大小固定,C#不支持动态数组。
从System.Array继承的对象
Rank维度
Length元素个数
int[] intArr = new int[]{10, 20};
foreach(int item in arr){}

数组协变:即使某个对象不是数组的基类型,我们也可以把它赋值给数组元素。
数组是引用类型数组。

clone方法:
克隆值类型数组会产生两个独立数组;
克隆引用类型数组会产生指向相同对象的两个数组。

列表
列表比数组更常用,因为列表更灵活。
声明列表的格式如下:
List<datatype> <var name> = new List<datatype>();
List<int> intList = new List<int>();
其他数据结构:队列、字典 (哈希表的实现)、哈希集合、只读集合、元组 (.Net 4+)

委托

包含具有相同签名和返回值类型的有序方法(实例/静态)列表的对象。

当委托被调用时,它调用列表中的每一个方法。

委托是面向对象的,而且是类型安全的。

委托和类一样,是一种类型。必须在被用来创建变量以及类型之前声明。

delegate void MyDel(int x);

返回类型和签名指定了委托接受的方法的形式。

委托声明与方法声明不同在于:以delegate关键字开头;没有方法主体。

MyDel devVar = new MyDel(myInstObj.MyM1);//创建委托并保存引用

或 MyDel devVar = myInstObj.MyM1;//在方法名称和其委托类型之间有隐式转换

MyDel delA = myInstObj.MyM1;
MyDel delB = SClass.OtherM2;
MyDel delC = delA + delB; //组合调用列表

委托是恒定的,委托对象被创建后不会再被改变。

MyDel delVar = inst.MyM1;//创建并初始化
delVar += SCl.M3;//增加方法
delVar -= SCl.M3;//移除方法

如果调用列表为空,则委托是null;
试图调用空委托会抛出异常;
试图删除委托中不存在的方法没有效果;
-=移除第一个匹配的实例;

delVar(55);//调用委托

调用带返回值的委托,最后一个方法返回的值就是委托调用返回的值。其他方法返回值都会被忽略。

调用带引用(ref)参数的委托,参数值会根据调用列表中的一个或多个方法的返回值而改变。在调用委托列表中的下一个方法时,参数的新值(不是初始值)会传给下一个方法。

匿名方法,是在初始化委托时内联声明的方法。
OtherDel del = delegate(int x){ return x + 20; };
不能显式声明返回值,但是在实现代码本身的行为必须通过返回一个在类型上与委托的返回类型相同的值来匹配委托的返回类型。
如果委托声明的参数列表包含了params参数,那么params关键字就会被匿名方法的参数列表忽略。

Lambda表达式
MyDel del = delegate(int x) { return x + 1; };//匿名方法
MyDel lel1 = (int x) => { return x + 1; };//表达式
MyDel lel2 = (x) => { return x + 1; };//表达式
MyDel lel3 = x => { return x + 1; };//表达式
MyDel lel4 = x => x + 1;//表达式

事件

事件其实就好像被简化的针对特殊用途的委托。注册到事件上的方法会在事件触发时被调用。

触发事件:调用(invoke)或触发事件的术语。当事件被触发时,所有注册到它的方法都会被依次调用。
发布者(publisher):让事件被其他类或结构可见并使用的类或结构。
订阅者(subscriber):把事件和发布者关联注册的类或结构。
事件处理程序(event handler):注册到事件的方法。可以在事件所在的类或结构中,或者在不同的类或结构中。

事件包含一个私有委托。

声明事件
public event EventHandler Elapsed;

事件是成员不是类型。隐式自动初始化为null。

        public event EventHandler Elapsed;
        private void OnOneSecond(object source, EventArgs args)
        {
            if (Elapsed != null)
            {
                Elapsed(source, args);
            }
        }

发布者类有一个作为成员的事件。
类包含了触发事件的代码。

标准事件的用法
public delegate void EventHandler(object sender, EventArgs e);

为了向自己的事件处理程序的第二个参数传入数据,并且又符合标准惯例,需要声明一个派生自EventArgs的自定义类。
使用自定义委托
public delegate void MyTCEventHandler(object sender, MyTCEventArgs e);
public event EventHandler<MyTCEventArgs> Elapsed;

System.Timers.Timer的Interval属性,指定触发事件间隔的毫秒数。

+=和-=运算符是事件允许的唯一运算符。这些运算符有预定义行为,我们可以修改这些运算符的行为。通过事件访问器来实现。
public event EventHandler Elapsed
{
add{...}
remove{...}
}

接口

接口是表示一组函数成员而不实现成员的引用类型。类和结构可以实现接口。
public interface Icomparable
{
   int CompareTo(object obj);
}

接口声明可以有任何的访问修饰符;但是接口的成员是隐式public的,不允许显式。

如果类从基类继承并实现接口,基类列表中的基类名称必须放在任何接口之前。
class Derived : MyBaseClass, IEnumerable, IEnumerator{}

不能直接通过类对象的成员访问接口。可以通过把类对象引用强制转换为接口类型来获取指向接口的引用。有了接口的引用,就可以使用点号来调用接口的方法。

as运算符
IliveBirth b = a as IliveBirth;
如果实现了接口,返回指向接口的引用;
如果没有实现接口,返回null。

如果一个类实现了多个接口,那么其中一些接口有相同签名和返回类型的成员。类可以实现单个成员来满足所有包含重复成员的接口。

实现接口的类可以从它的基类继承实现的代码。

显式接口成员实现,使用限定接口名称来声明,由接口名称和成员名称以及它们中间的点分隔符号构成。必须总是通过接口的引用来访问。

接口也可以继承自一个或多个接口。类只能继承一个父类。

转换

对于有符号类型的转换而言,额外的高位用源表达式的符号位进行填充。

装箱:转换任何值类型到object类型/System.ValueType类型;
拆箱:转换装箱的值到原始类型。

溢出检测上下文,如果丢失会抛出OverflowException异常
运算符:
checked(表达式)
unchecked(表达式)
语句:(可以嵌套)
unchecked
{
  ...
  checked
  {
   ...
  }
}

知道发生数据丢失时转换会如何处理很重要。
double到整数:如果结果值不在目标类型的范围内,则抛出OverflowException;
double到float:如果太小而不能用float表示,那么值设置为正或负0;如果太大,而不能用float表示,则会被设置为正或负无穷大。
float或double到decimal:值太大而不能用decimal表示,那么设置为0;如果太大,抛出OverflowException异常。
decimal到float或double:总是成功,但是有可能会损失精度。

父类强制转换成子类会导致InvalidCastException异常,但不是编译错误。

有效显式引用转换
1、从衍生类到基类的转换;
2、源引用是null;
3、由源引用指向的实际数据可以被安全地进行隐式转换。

装箱转换
是一种接受值类型的值,根据这个值在堆上创建一个完整的引用类型对象并返回对象引用的隐式转换。

int i = 12;
object o = null;
o = i;
在内存中创建int类型对象;
复制i的值到这个对象;
把int对象的引用返回给i;

任何值类型ValueTypes都可以隐式转换为object、System.ValueType或InterfaceT(如果ValueTypeS实现了InterfaceT)。

拆箱转换
是把装箱后的对象转换回值类型的过程。
尝试拆箱一个值为非原始类型时会抛出一个InvalidCastException异常。

用户自定义转换:除了标准转换,我们还可以为类和结构定义隐式和显式转换。

public static implicit operator TargetType(SourceType Identifier)
{
     ...
     return ObjectOfTargetType;
}
将Person转换为int
public static implicit operator int(Person p)
{
     return p.Age;
}

is运算符
Expr is TargetType; //返回bool
如果Expr表达式可以通过以下方式被成功转换为目标类型,运算符返回true。
引用转换、装箱转换、拆箱转换。不能用于用户自定义转换。

as运算符
和强制类型转换运算类似,只是它不抛出异常。如果转换失败,它把目标引用设置为null而不是抛出异常。
Expr as TargetType;
Expr源表达式;TargetType目标类型,必须是引用类型;

只能用于引用转换和装箱转换,不能用于用户自定义转换或到值类型的转换。

泛型

泛型允许我们声明类型参数化的代码,我们可以用不同的类型进行实例化。也就是说,我们可以用“类型占位符”来写代码,然后在创建类的实例时提供真实的类型。

泛型声明实例:
class MyStack <T>
{
     int StackPointer = 0;
     T [] StackArray;
     public void Push(T x) {....}
     public T Pop(){...}
}
T代表类型的占位符,也不一定要是字母T,可以是任何标识符。T又称为类型参数。

class SomeClass <T1, T2>
{
     public T1 SomeVar = new T1();
     public T2 OtherVar = new T2();
}
SomeClass<short, int> myInst;
myInst = new SomeClass<short, int>();
var mySc = new SomeClass<short, int>();
用var关键词使编译器使用类型引用;

只有符合约束的实参才能用于类型参数。通过where子句来实现约束。
class MyClass <T1, T2, T3>
                         where T2 : Customer
                         where T3 : IComparable
{...}
5种类型约束:
类名:只有这个类型的类或从它继承的类才能用作类型实参;
class:任何引用类型,包括类、数组、委托和接口都可以用作实参;
struct:任何值类型都可以被用作类型实参;
Interfacename:只有这个接口或实现这个接口的类型才能用作实参;
new():任何带有无参公共构造函数的类型都可以用作实参,这叫做构造函数约束。

泛型结构:
struct PieceOfData<T>
{
     public PieceOfData(T value) {_Data = http://www.mamicode.com/value; }
     private T _Data;
     public T Data
     {
          get { return _Data; }
          set { _Data = http://www.mamicode.com/value; }
     }
}

泛型接口:
interface IMyIfc<T>
{     
     T ReturnIt(T inValue);
}
class Simple<S> : IMyIfc<S>
{
     public S ReturnIt(S inValue)
     {
          return inValue;
     }
}
class Simple2 : IMyIfc<int>, IMyIfc<string>
{    
     public int ReturnIt(int inValue)
     { return inValue; }
     public string ReturnIt(string inValue)
     { return inValue; }
}

实现泛型类型接口时,必须没有可能的类型实参组合会在类型中产生两个重复的接口。

泛型委托:
delegate R MyDelegate<T, R>(T value);
delegete void MyDelegate<T>(T value);
var myDel = new MyDelegate<string>(Simple.PrintString);

泛型方法:
public void PrintData<S, T>(S p) where S: Person{...}

泛型类的扩展方法:
必须声明为static;
必须是静态类的成员;
第一个参数类型中必须有关键字this,后面是扩展的泛型类的名字;
public static void Print<T>(this Holder<T> h){...}

枚举数和迭代器

数组可以按需提供一个叫枚举数的对象。枚举数可以依次返回请求的数组的元素。枚举数“知道”项的次序并且跟踪它在序列中的位置,然后返回请求的当前项。

可枚举类型实现GetEnumerator方法。

实现枚举数的方式:
IEnumerator/IEnumerable接口;
IEnumerator<T>/IEnumerable<T>接口;
不使用接口形式;

IEnumerator接口包含三个方法:Current、MoveNext和Reset

IEnumerable接口只有一个方法:GetEnumerator,它返回对象的枚举数。

迭代器
迭代器块是有一个或多个yield语句的代码块。迭代器块中的代码描述了如何枚举元素。
yield return执行了序列中返回的下一项;
yield break指定在序列中没有更多项;

public IEnumerator<string> BlackAndWhite()
{
     yield return "black";
     yield return "gray";
     yield return "white";
}

LINQ

用于提供查询数据能力的一个新特性。
LINQ(发音为link)代表语言集成查询(Language Integrated Query);
LINQ是.NET框架的扩展,它允许我们以数据库查询的方式查询数据集合;
C# 3.0包含集合LINQ到语言中的一些扩展,允许我们从数据库、程序对象集合以及XML文档中查询数据。

匿名类型:
var student = new {LName="Jones", FName="Mary", Age=19, Major="History"};

var student = new { Age=19, Major, Other.Name };
赋值形式;标识符形式;成员访问表达式;

方法语句:
int[] numbers = {2, 5, 28, 31};
var numsMethod = numbers.Where(x => x < 20);

int[] arr1 = {10, 11, 12, 13};
var query = from item in arr1
                    where item < 13
                    select item;

int[] numbers = { 2, 12, 5, 15 };
IEnumerable<int> LowNums = from n in numbers
                          where n < 10
                          select n;

join子句
var query = from s in students
                 join c in studentsInCourses on s.StID equals c.StID;

from子句
var groupA = new[]{3, 4, 5, 6};
var groupB = new[]{6, 7, 8, 9};
var someInts = from a in groupA
                       from b in groupB
                       where a > 4 && b <= 8
                       select new {a, b, sum = a + b };

let子句:接受一个表达式的运算并且把它赋值给一个需要在其他运算中使用的标识符;
var someInts = from a in groupA
                       from b in groupB
                       let sum = a + b
                       where sum == 12
                       select new {a, b, sum };

where子句可以多个;

orderby子句:接受一个表达式并根据表达式依次返回结果项,可以多个用逗号隔开;
默认升序,升序关键字ascending,降序关键字descending;

group子句:
var query = form student in students
                 group student by student.Major;
作为分组依据的项叫做键key。

查询延续:
var someInts = from a in groupA
                       from b in groupB on a equals b
                       into groupAandB
                       from c in groupAandB
                       select c;

XML类
最重要的类包括:XElement、XAttribute和XDocument

XDocument employees1 =
    new XDocument(
        new XElement("Employees",
            new XElement("Name", "Bob Smith"),
            new XElement("Name", "Sally Jones")
        )
    );
employees1.Save("EmployeesFile.xml");
XDocument employees2 = XDocument.Load("EmployeesFile.xml");
Console.WriteLine(employees2);

EmployeesFile.xml内容:
<?xml version="1.0" encoding="utf-8"?>
<Employees>
  <Name>Bob Smith</Name>
  <Name>Sally Jones</Name>
</Employees>

查询XML的方法:
Nodes
Elements
Element
Descendants
DescendantsAndSelf
Ancestors
AncestorsAndSelf
Parent

增加/删除节点以及操作XML:Add()、AddFirst、AddBeforeSelf、AddAfterSelf、Remove、RemoveNodes

使用XML属性:属性提供了有关XElement节点的额外信息,它放在XML元素的开始标签中。
new XAttribute("color", "red");
<root color="red">
</root>

节点的其他类型:XComment、XDeclaration以及XProcessingInstruction

使用LINQ to XML的LINQ查询:
XDocument xd = XDocument.Load("SimpleSample.xml");
XElement rt = xd.Element("MyElements");
var xyz = from e in rt.Elements()
               where e.Name.toString().Length == 5
               select e;

异步编程简介

当我们启动一个程序时,系统在内存中创建一个新的进程。进程就是一组资源,它们构成了一个正在运行的程序。这些资源包括虚拟地址空间、文件句柄以及程序启动需要的其他东西的载体。

如果委托对象在调用列表中只有一个方法(之后会叫做引用方法),它就可以异步执行这个方法。委托类有两个方法,叫做BeginInvoke和EndInvoke。它们就是用来这么做的。

预处理指令

源代码指定了程序的定义。预处理指令指示编译器如何处理源代码。

#define identifier
#undef identifier
#if expression
#elif expression
#else
#endif
#region name
#endregion name
#warning message
#error message
#line indicator
#pragma text

例子:

#define DEBUG

...

#if DEBUG
//这里的代码会被执行
#else
//这里不会执行
#endif

反射和特性

有关程序及其类型的数据被称作元数据,它们保存在程序的程序集中;
程序在运行时,可以查看其它程序集或其本身的元数据。一个运行的程序查看本身的元数据或其他程序的元数据的行为叫做反射。

Type类成员:Name、Namespace、GetFields、GetProperties、GetMethods
获取Type对象:
Type t = myInstance.GetType();
Type t = typeof(DerivedClass);

特性是一种允许我们向程序的程序集增加元数据的语言结构。
特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集。
[ Serializable ]
public class MyClass
{...}

[ MyAttribute("Simple class", "Version 3.57") ]
public class MyOtherClass
{...}

预定义特性:CLSCompliant Serializable NonSerialized Obsolete DLLImport WebMethod AttributeUsage

全局特性:用assembly和module来使用显式目标把特性设置在程序集或模块级别。
程序级级别的特性必须放置在任何命名空间之外,并且通常放置在AssemblyInfo.cs文件中;
AssemblyInfo.cs文件通常包含有关公司、产品以及版权信息的元数据。

自定义特性
public sealed class MyAttributeAttribute : System.Attribute
{...}
每个特性至少必须有一个公共构造函数。

用Type的IsDefined方法检测某个特性是否应用到了某个类上。
使用GetCustomAttributes方法返回应用到结构的特性的数组。

其他主题

string和StringBuilder
格式化数字字符串:
     Console.WriteLine("The Value: {0:C}.", 500 );//格式化货币
     Console.WriteLine("The Value: {0,10}.", 500 );//在10字符的字段中右对齐
标准数字格式化说明符;
把字符串解析为数字值:double d = double.Parse("25.873");另一个方法TryParse,如果解析失败,返回false。

可空类型:创建一个值类型的变量并标注它为有效或无效。
int? myNInt = 28;
if( myNInt != null ) {...}
可空类型通过一个叫做System.Nullable<T>的.NET类型来实现。

Main方法
static void Main{...}
static void Main(string[] args){...}
static int Main(){...}
static int Main(string[] args){...}//成功返回0
可以声明为public和private

/// 表示文档注释

嵌套类型
class MyClass
{
     classMyCounter
     {...}
     ...
}


文档信息

  • 版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
  • 原文网址:http://blog.csdn.net/cdztop/article/details/38644345
  • 最后修改时间:2014年08月17日 21:42