.NET精辟要点整理
和Close()的区别
要实现一个具有Dispose()功能的类,首先该类必须继承自一个具有Close()方法的类,并自己实现一个Dispose(bool)方法,此函数是Protected型的重载函数.
注意,其实Close()方法里面调用了IDisposable接口的Dispose()方法(此方法是显式实现的,请查阅如果显式实现接口方法),而Dispose()方法里面又调用了Dispose(bool)方法.所以,如果你要写一个带有释放资源功能的类,你只需实现Dispose(bool)方法即可.
提示:你最好在Dispose(bool)方法里,实现托管释放和非托管释放,按false/true区别,并且,为了保险起见,在Dispose(bool)方法中,也要释放父类的资源(因为子类要执行父类的构造函数,如果父类在它的构造函数里申请了资源,那当然要释放,如果没有的话,就可选了,但我觉得,最好释放一下,没坏处).
class MyClass : SysClass //实现一个自己类里的Close()方法
{
private IntPtr m_anotherMemory;
private Bitmap m_anotherImage;
private bool m_disposed = false;
public MyClass()
{
m_anotherMemory = Marshal.AllocCoTaskMem(20);
m_anotherImage = new Bitmap(25,25);
}
//实现Dispose(bool)
//如果传入false,就只释放非托管资源;传入true,全部释放
protected override void Dispose(bool isDisposing)
{
if(!m_disposed)
{
if(isDisposing)
{
//在此处释放托管资源
m_anotherImage.Dispose();//m_anotherImage就是托管资源
}
//在此处释放非托管资源
Marshal.FreeCoTaskMem(m_anotherMemory);
//子类会执行父类的构造函数,这里还需释放父类的
base.Dispose(isDisposing);
m_disposed = true;
}
}
~MyClass()
{
//假如您有非托管资源,却忘记手动释放,不用担心,这里会执行释放
Dispose(false);
}
}
public static void Main (string[] args)
{
SysClass sc = new MyClass();
sc.Close(); //正确
sc.Dispose(); //错误
((IDisposable)sc).Dispose(); //正确
}
和Override的区别
override相当于C++中的重载,C++中的重载可以是同名且不同参(数目)的,而override则是样子一模一样的方法的重载,需要与virtual关键字配合使用;
new,说实话,不写也无妨,只是编译器会报警告,而它通常出现在子类与父类同名的函数中.
关键字
使参数按引用传递.若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字.
public class MyClass
{
private int num = 256;
public void Show()
{ Console.WriteLine(num); }
public void Set(ref int num)
{ this.num = num; }
public static void Main ()
{
MyClass m = new MyClass();
int value = 1024;
m.Set(ref value);
//输出 1024
m.Show();
}
}
读写INI文件
//申明INI文件的写操作函数WritePrivateProfileString()
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
//申明INI文件的读操作函数GetPrivateProfileString()
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
private void readIni_Click(object sender, EventArgs e)
{
StringBuilder strb = new StringBuilder();
int get_val = GetPrivateProfileString("name", "sex", "", strb, 255, "test.ini");
MessageBox.Show(strb.ToString());
}
不能有static成员、默认public但不写、子类方法若与父类同须用new、实现父类全部方法.
显式说明的接口成员最优先实现;
如果两个或多个父接口中存在同名成员,就产生二义性.此时,最好使用显式声明.
public class MyClass
{
public interface Animal
{ void Walk(); }
public interface Person : Animal
{ void Walk(); }
public class Man : Person
{
//父接口和爷爷接口有两个同样的方法,需显式实现,不然不知道哪个对哪个
//显式实现接口方法是public的,但不需要加public,但它是public的.非显式的可要加上public哦!
void Person.Walk()
{ Console.WriteLine("Person is walking..."); }
void Animal.Walk()
{ Console.WriteLine("Animal is walking..."); }
}
public static void Main ()
{
Man m = new Man();
Person p = (Person)m;
//显式接口的访问:必须通过接口的对象访问
p.Walk();
Animal a = (Animal)m;
a.Walk();
}
}
Output:
Person is walking...
Animal is walking...
abstract修饰符可以用于类、方法、属性、事件和索引指示器.抽象类不能被实例化;不能用sealed修饰符让它无法被继承;非抽象子类必须实现所有抽象父类的方法;抽象类中的方法是隐式的Virtual方法.
public class MyClass
{
public abstract class AMedia
{
public abstract void Play();
//抽象类里可以实现方法(千万不要在该方法前面加上abstract)
public void Close()
{ Console.WriteLine("have closed..."); }
}
public class Audio : AMedia
{
//记得override
public override void Play()
{ Console.WriteLine("is plaing..."); }
}
public static void Main ()
{
Audio a = new Audio();
a.Play();
a.Close();
}
}
抽象类 是从一系列对象中抽象出来的概念,因此反映事物的内部共性;
接口 是为了满足外部调用而定义的一个功能约定,因此反映的是事物的外部特性.
不同点:抽象类可以包含实现的类,而接口只能包含定义;抽象类的抽象方法默认隐式Virtual,而接口类方法默认public;抽象类不能被实例化,接口却可以;
相同点:都能被继承;都需要实现父类的所有方法;
分析对象,提炼内部共性形成抽象类,用以表示对象本质,取”是什么”;
为外部提供调用或功能需要扩充时优先使用接口.
需使用类名访问
public class MyClass
{
static int staNum = 100;
public static void Main ()
{ MyClass.staNum = 10000; }
}
和 static readonly的区别
1. const 是在编译期间初始化;
2. static readonly 是在运行期间初始化.
调用方法: 都需要使用类名访问!
关键字
1. 修饰类时,该类不能被继承;
2. 修饰方法和属性时,该方法和属性也不能被继承.(修饰方法时,sealed总是和override连用,由此说明该方法肯定是virtaul的)
sealed类可以有虚函数吗? 可以,但基类中的虚函数隐式转换成非虚函数.
class Base
{
public virtual void Show()
{ Console.WriteLine("I am Base..."); }
}
sealed class Son : Base
{
// Base中的虚函数Show()已隐式转换为非虚函数了.
//Son类不能自己再定义虚函数!
}
像数组一样,唯一不同的是,[]中不局限于int型.
public int this[int Index]
{
get { }
set { }
}
不同点: 类是引用类型(在堆上,手动释放),结构是值类型(在栈上,自动释放)
相同点: 结构也有构造函数,但前提是一个带参数的构造函数;
效率: 类实例的赋值只是复制了引用;而结构的赋值却是产生一个新的对象.
修饰符
引用空间名,为空间名起别名;
释放资源.
不能有参数,且只能操作静态成员;
public class Static
{
static int i = 100;
static Static()
{
Static.i = 999;
}
}
若父类没有定义无参数的构造函数,在定义子类构造函数时,需显式初始化父类的构造函数
public class Dad
{
private int dadAge;
public Dad(int age)
{ dadAge = age; }
}
public class Son : Dad
{
private int sonAge;
public Son(int age)
: base(0) //显式初始化父类的构造函数
{ sonAge = age; }
}
总结:
到底是值类型,还是引用类型?
答:我可以很肯定的告诉你,是引用类型,只不过它在某些操作上会表现出值类型的特征.如函数参数,==时.
string的一个特殊性就在于它”不会变”.
何为”不会变”,展示一下:
public class MyClass
{
public static void Main ()
{
string str1 = "I am a number";
string str2 = str1;
Console.WriteLine("str1 = " + str1);
Console.WriteLine("str2 = " + str2);
str1 = "I am another number";
Console.WriteLine("after str1 changed... str1 = " + str1);
Console.WriteLine("after str1 changed... str2 = " + str2);
}
}
Output:
str1 = I am a number
str2 = I am a number
after str1 changed...str1 = I am another number
after str1 changed...str2 = I am a number
public static void Main ()
{
string str = "china";
Change(str);
Show(str);
}
//这里的参数传递,实质上是 = 过程,和上例一样,会产生一个新的引用
public static void Change(string str)
{ str = "china yangzhou "; }
public static void Show(string str)
{ Console.WriteLine(str); }
Output:
china
和String的区别
String虽然是引用类型,但在赋值时却会产生新的对象;
StringBuilder则不会,所以在处理大量字符串时,它是首选.
该关键字用在方法的参数列表中,为该方法参数提供了可变的能力.它只能出现一次,且只能定义在所有参数最后.
//params 定义的参数后面不可以再定义其它参数
public static void UseParams(string str, params object[] list)
{
Console.WriteLine(str);
for (int i = 0; i < list.Length; i++)
{ Console.WriteLine(list[i]); }
}
static void Main (string[] args)
{
String[] str = new string[] { "I", "LOVE", "YOU" };
Program.UseParams("Hello", str);
}