1. 抽象类/方法
1.1 抽象类
通过在类定义前面放置关键字 abstract
,可以将类声明为抽象类;抽象类不能实例化。
public abstract class A
{
// Class members here.
}
抽象类的用途是提供一个可供多个派生类共享的通用基类定义。
例如,类库可以定义一个抽象类,将其用作多个类库函数的参数,并要求使用该库的程序员通过创建派生类来提供自己的类实现。
1.2 抽象方法
抽象类也可以定义抽象方法。 方法是将关键字 abstract
添加到方法的返回类型的前面。
public abstract class A
{
public abstract void DoWork(int i);
}
抽象方法没有实现,所以方法定义后面是分号,而不是常规的方法块。 抽象类的派生类必须实现所有抽象方法。 当抽象类从基类继承虚方法时,抽象类可以使用抽象方法重写该虚方法。
2. 密封类/方法
2.1 密封类
密封类是修饰为 sealed
的类,不能有子类;一般只有系统中的一些基本类声明为密封类。
public sealed class SealedClass
{
}
2.2 密封方法
密封方法只能是在已经被重写的方法中定义,表示这个方法不可以再被重写;
class BaseClass
{
public virtual void Move()
{
//...
}
}
class DerivedClass : BaseClass
{
public sealed override void Move() //只能在重写的方法里定义sealed
{
base.Move();
}
}
密封类和密封方法的作用,是放置重写某些类导致代码的混乱,或者一些出于商业上的原因。
3. 静态类/类成员
3.1 静态类
静态类基本上与非静态类相同,但存在一个差异:静态类无法实例化,不能继承或被继承;且只包含静态成员;不能包含实例构造函数,但可以包含静态构造函数,且不能对其构造函数使用访问修饰符。
public static class DemoStaticClass
{
public static string ReturnValue(string value)
{
return value;
}
}
3.3 静态方法/字段
public class Automobile
{
public static int NumberOfWheels = 4;
public static void Drive() { }
}
4. 扩展方法
扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型,现有类型既可以是 int
,string
等数据类型,也可以是自定义的数据类型。
扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用,调用扩展方法与调用在类型中实际定义的方法之间没有明显的差异。
扩展方法的第一个参数指定该方法作用于哪个类型,并且该参数以 this
修饰符为前缀。 扩展方法当然不能破坏面向对象封装的概念,所以只能是访问所扩展类的 public
成员。
扩展方法最终其实还是被编译器处理为普通静态方法的调用,本质上还是静态方法的调用,所不能访问类的外部成员。
4.1 一般扩展方法
必要条件
- 扩展方法所在的类必须为静态类
- 扩展方法必须为静态方法
- 第一个参数必须为需要扩展的类型且以
this
为前缀
代码实现
public class Person
{
public string Name { set; get; }
public int Age { set; get; }
}
public static class MyExtensions
{
#region 基本类型扩展方法
public static int GetLength(this String value)
{
return value.Length;
}
public static int GetCount(this string value,int len)
{
return value.Length + len;
}
#endregion
#region 自定义类型扩展方法
public static bool GetBIsChild(this Person oPerson)
{
if (oPerson.Age >= 18)
return false;
else
return true;
}
#endregion
}
使用扩展方法
int len = "李白".GetLength();
int count = "李白".GetCount(2);
var oPerson1 = new Person();
oPerson1.Age = 20;
var bIsChild = oPerson1.GetBIsChild();
4.2 泛型扩展方法
定义方法
public static class MyExtensions
{
public static bool ValIsNull<T>(this T val)
{
if (val == null) return false;
else return true;
}
public static IList<T> ForeachOne<T>(this IList<T> sources)
{
return sources;
}
}
使用方法
string value = "李白";
value.ValIsNull();
Cval cval = new Cval();
cval.ValIsNull();
List<string> str_list = new List<string>();
str_list.ForeachOne();
List<Cval> Cval_list = new List<Cval>();
Cval_list.ForeachOne();
4.3 泛型委托方法
声明方法
public static class CustomExtensions
{
public static TSource Handle<TSource>(this TSource source, Func<TSource, bool> predicate)
{
if (predicate(source)) return source;
else return default(TSource);
}
public static List<TSource> MyWhere<TSource>(this List<TSource> source, Func<TSource, bool> predicate)
{
List<TSource> list = new List<TSource>();
foreach (var item in source)
{
if (predicate(item)) list.Add(item);
}
return list;
}
static Func<TSource, bool> CombinePredicates<TSource>(Func<TSource, bool> predicate1, Func<TSource, bool> predicate2)
{
return x => predicate1(x) && predicate2(x);
}
}
使用方法
class Program
{
static void Main(string[] args)
{
string value_isnull = "李白".Handle(x => x != null);
Console.WriteLine(value_isnull);
string value_len = "李白".Handle(x => x.Length > 6);
Console.WriteLine(value_len);
List<string> list = new List<string> { "1", "12" };
var new_list = list.MyWhere(x => x.Length > 1);
foreach (var item in new_list)
{
Console.WriteLine(item);
}
}
}
5. 深/浅拷贝
说明:深拷贝和浅拷贝只是拷贝的两种现象(实现),不是技术。
5.1 两者区别
浅拷贝是指将对象中的数值类型的字段拷贝到新的对象中,而对象中的引用型字段则指复制它的一个引用到目标对象。如果改变目标对象中引用型字段的值他将反映在原始对象中,也就是说原始对象中对应的字段也会发生变化。
深拷贝与浅拷贝不同的是对于引用的处理,深拷贝将会在新对象中创建一个新的和原始对象中对应字段相同(内容相同)的字段,也就是说这个引用和原始对象的引用是不同的,我们在改变新对象中的这个字段的时候是不会影响到原始对象中对应字段的内容。
示例代码
Cval cval = new Cval();
cval.num = 1;
Person person1 = new Person();
person1.Age = 1;
person1.cv = cval;
Person person2 = new Person();
person2.Age = person1.Age;
person2.cv = person1.cv;
person1.Age = 10;
person1.cv.num = 10;
Console.WriteLine($"person1:{person1.Age}-{person1.cv.num}");
Console.WriteLine($"person2:{person2.Age}-{person2.cv.num}");
示例结果
person1:10-10
person2:1-10
6. Action回调方法
6.1 基本使用
定义回调
public class Helper
{
public void Show(string value, Action<string> callBack)
{
callBack("姓名:" + value);
}
public void ShowTwo(string value, int age, Action<string, int> callBack)
{
callBack("姓名:" + value, age + 1);
}
}
使用回调
static void Main(string[] args)
{
Helper helper = new Helper();
helper.Show("李白", val => Console.WriteLine(val));
helper.ShowTwo("李白", 15, (val, age) => Console.WriteLine($"{val},{age}"));
}