一种特定于平台的类型,用于表示指针或句柄。
表示操作系统句柄的包装类。这个类必须被继承。
生命周期:一旦创建直到应用程序结束才会消失,全局。
方法被static修饰,可以直接通过类名.方法名
调用
internal class TestMethodClass
{
static void Main(string[] args)
{
string a = TestMethodClass.StaticMethod();
Console.Read();
}
public static string StaticMethod() {
return "This is Static Method";
}
}
类似于java,默认是有一个无参构造方法,但是不会显示出来。可以自定义多个有参构造方法。在实例化类的时候(也就是生命周期开始时)会去调用构造方法在内存中开辟一段空间,存储这个实例化对象。
方法名与类名一致。
声明折构方法:~类名
一般在GC回收时调用,用来释放对象。一般很少用到。
这里涉及到托管资源的概念,简单来讲GC机制会自动回收一些资源,但是有一些资源不在GC回收机制范围内,这部分就是非托管资源,而折构方法一般用在回收非托管资源上面,比如数据库链接。
C#中IDisposable接口的主要用途是释放非托管资源。当不再使用托管对象时,垃圾回收器会自动释放分配给该对象的内存。但无法预测进行垃圾回收的时间。另外,垃圾回收器对窗口句柄或打开的文件和流等非托管资源一无所知。将此接口的Dispose方法与垃圾回收器一起使用来显式释放非托管资源。当不再需要对象时,对象的使用者可以调用此方法。Dispose()专门回收GC机制回收不了的非托管资源
使用时大概如下:
在一个类中实现IDisposable
,重写Dispose
方法,方法内为回收非托管资源的逻辑,之后声明折构方法:~类名
,折构方法在对象销毁时触发,而在折构方法内部调用重写的Dispose()
方法实现非托管资源的回收。
internal class DisposeTest : IDisposable
{
public void Dispose()
{
throw new NotImplementedException();
}
}
virtual
关键词修饰override
关键词修饰base.虚方法名
来调用原方法内的逻辑。也可以修改虚方法内容改为新的逻辑,即便修改后也不会更改原虚方法内的方法逻辑。public class VirtualMethod
{
public virtual int Calc(int a, int b)
{
return a + b;
}
}
public class VirtualMethodChild : VirtualMethod {
public override int Calc(int a, int b)
{
return base.Calc(a, b);
}
}
abstract关键词修饰,抽象方法必须写到抽象类里面。一般由抽象类定义抽象方法的规范(入参/返回值)之后子类实现抽象方法,完成方法内部具体逻辑。
使用场景,当一个类设置了sealed修饰符,那这个类就是密封的,不可以被继承,也就不可以通过继承的方式重写这个类中的方法然后去调用了。
0x01 扩展方法
比如这里拿sealed
修饰了一个类,但是想调用这个里面的getString
方法
internal sealed class Class4
{
public string getString() {
return "string";
}
}
定义扩展方法:静态类+静态方法+this 引用类型
调用时直接对象名.方法名即可调用
static class Program
{
public static void testExtendMethod(this ExtendClass extclass) {
extclass.getString();
}
}
0x02 扩展接口
接口
internal interface Interface1
{
int Add(int a, int b);
}
定义扩展方法,同时新增了一个方法,这样当有一个新的类继承原来的接口Interface1
时也可以调用到新增的扩展方法ExtendAdd2
public static class ExtendClassTest
{
public static int ExtendAdd1(this Interface1 in1, int a, int b) {
return a + b;
}
public static int ExtendAdd2(this Interface1 in1, int a, int b)
{
return a - b;
}
}
允许延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。换句话说,泛型允许您编写一个可以与任何数据类型一起工作的类或方法。
比如设置数组,用object
赋值的时候 元素可以为int 、string等其他类型。和java泛型差不多。再比如下面的使用泛型类,在类名后跟<T>
,占位符不一定是T
其他的也可以,但是默认是写成T
。可以等到真正使用的时候再去设置这个类声明的一个类型。再有这里泛型不一定只是定义一个,也可以定义多个。
public class MyGenericArray<T>
{
private T[] array;
public MyGenericArray(int size)
{
array = new T[size + 1];
}
public T getItem(int index)
{
return array[index];
}
public void setItem(int index, T value)
{
array[index] = value;
}
}
class Tester
{
static void Main(string[] args)
{
// 声明一个整型数组
MyGenericArray<int> intArray = new MyGenericArray<int>(5);
// 设置值
for (int c = 0; c < 5; c++)
{
intArray.setItem(c, c*5);
}
// 获取值
for (int c = 0; c < 5; c++)
{
Console.Write(intArray.getItem(c) + " ");
}
Console.WriteLine();
// 声明一个字符数组
MyGenericArray<char> charArray = new MyGenericArray<char>(5);
// 设置值
for (int c = 0; c < 5; c++)
{
charArray.setItem(c, (char)(c+97));
}
// 获取值
for (int c = 0; c < 5; c++)
{
Console.Write(charArray.getItem(c) + " ");
}
Console.WriteLine();
Console.ReadKey();
}
}
泛型方法,在方法名后跟<T>
class Program
{
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, b;
char c, d;
a = 10;
b = 20;
c = 'I';
d = 'V';
// 在交换之前显示值
Console.WriteLine("Int values before calling swap:");
Console.WriteLine("a = {0}, b = {1}", a, b);
Console.WriteLine("Char values before calling swap:");
Console.WriteLine("c = {0}, d = {1}", c, d);
// 调用 swap
Swap<int>(ref a, ref b);
Swap<char>(ref c, ref d);
// 在交换之后显示值
Console.WriteLine("Int values after calling swap:");
Console.WriteLine("a = {0}, b = {1}", a, b);
Console.WriteLine("Char values after calling swap:");
Console.WriteLine("c = {0}, d = {1}", c, d);
Console.ReadKey();
}
}
这里直接贴图,简单了解,后面遇到了再深入跟一下。
泛型约束,通过在参数声明之后,通过where关键词指定传入的泛型的类型约束,比如这里where T:new()
就表示传来的泛型T必须是一个类,可以通过new去实例化。
常用的约束如下,接口约束可以有多个
out修饰的参数只能当作返回值用,不可以被用做内部的具体方法的入参。
in修饰的只能当作参数,不能当作返回值。
C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。
委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。
声明格式如下
delegate <return type> <delegate-name> <parameter list>
上面的委托可被用于引用任何一个带有一个单一的 string 参数的方法,并返回一个 int 类型变量。
这里感觉就是在内部回去匹配一个入参数量为1,类型为string,且返回值类型为int的方法,并用MyDelegate作为该方法的引用。
public delegate int MyDelegate (string s);
个人感觉类似于一个代理机制,实例化DelegateTest
时传入相应的(返回值类型,入参数量,入参类型)方法,即可通过DelegateTest
的实例化对象调用该方法(感觉是创建了一个对于该方法的引用)
delegate string DelegateTest (string str);
namespace Reflection
{
public class MyReflection
{
public static string Base = "base";
public static string Hello(string str) {
Base += "Hello " + str;
return Base;
}
public static string World(string str) {
Base += "World " + str;
return Base;
}
static void Main(string[] args)
{
DelegateTest delegateTest1 = new DelegateTest(Hello);
DelegateTest delegateTest2 = new DelegateTest(World);
Console.WriteLine(Base);
delegateTest1("delegateTest1");
Console.WriteLine(Base);
delegateTest2("delegateTest2");
Console.WriteLine(Base);
Console.ReadKey();
}
output:
base
baseHello delegateTest1
baseHello delegateTest1World delegateTest2
委托对象可使用 "+" 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。
执行的话应该是也有顺序的,按照+
前后的顺序来执行。
delegate string DelegateTest (string str);
namespace Reflection
{
public class MyReflection
{
public static string Base = "base";
public static string Hello(string str) {
Base += "Hello " + str;
return Base;
}
public static string World(string str) {
Base += "World " + str;
return Base;
}
static void Main(string[] args)
{
DelegateTest delegateTest1 = new DelegateTest(Hello);
DelegateTest delegateTest2 = new DelegateTest(World);
DelegateTest dt = delegateTest1 + delegateTest2;
dt("delegateTest");
Console.WriteLine(Base);
output:
baseHello delegateTestWorld delegateTest
所有内容仅限于维护网络安全学习参考
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.cnblogs.com/CoLo/p/16246484.html
内容来源于网络,如有侵权,请联系作者删除!