Effective-c#-3 使用C#表达式

21 限制类的可见性

就是说能隐藏的尽量隐藏,后面改起来也会轻松点。

22 通过定义并实现接口方法替代继承

也是一个老生常谈的东西了,面向接口编程。

23 理解接口方法和虚方法的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
interface IMsg
{
void Message();
}

public class A : IMsg
{
public void Message()
{
Console.WriteLine("A");
}
}

public class B : A
{
public void Message()
{
Console.WriteLine("B");
}
}

// 调用
B b = new B();
b.Message(); // 打印 B
IMsg m = b as IMsg;
m.Message(); // 打印 A

实际上B中的Message是一个新的方法,只不过由于同名,把基类的同名方法给覆盖了。

若要让下面那个调用也打印出B,可以用new修饰B.Message()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class B : A
{
public new void Message()
{
Console.WriteLine("B");
}
}

// 调用
B b = new B();
b.Message(); // 打印 B
IMsg m = b as IMsg;
m.Message(); // 打印 B
A a = b as A;
a.Message(); // 打印 A

该方法的缺点当使用A类型引用B对象时,仍会调用A的方法。

欲修改此行为,应直接修改基类的方法为虚方法,再于派生类方法前修饰override关键字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class A : IMsg
{
public virtual void Message()
{
Console.WriteLine("A");
}
}

public class B : A
{
public override void Message()
{
Console.WriteLine("B");
}
}

如果A类根本不想实现Message方法,把A类变成抽象类即可。

1
2
3
4
public abstract class A : IDispose
{
public abstract void Message();
}

若是派生类不想此方法再被覆写,可用sealed关键字修饰

1
2
3
4
5
6
public class B : A
{
public sealed override void Message()
{
}
}

24 用委托实现回调 & 25 用事件模式实现通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class EventDispatcher
{
public static delegate void OnEnterSceneHandler(string sceneName);
public static event OnEnterSceneHander OnEnterScene;

public static void DispatchEnterSceneEvent(string sceneName){
if(OnEnterSceneHandler != null)
{
OnEnterSceneHandler(sceneName);
}
}
}

// 注册事件
EventDispatcher.OnEnterScene += this.OnEnterScene;
// 发放事件
EventDispatcher.DispatchEnterSceneEvent("Home");

26 避免返回堆内部类对象的引用

参见18 区分值类型和引用类型。

27 让类型支持序列化

应该尽可能地为类型添加序列化支持,只要类型表示的不是UI控件、窗体或者表单。理由是如果成员被私有隐藏起来了,那么派生类想要实现序列化时不可能的。

当成员变量都是可序列化的时候(.Net基础类型int, string, etc…),为类型MyClass添加序列化支持只需要在最前头添加[Serilizable]即可。但是如果成员变量里有不可序列化的类型,那么在序列化MyClass的时候就会抛出运行时错误。

在成员变量前添加[NonSerialized]特性可以避免被序列化。如一些缓存用的成员变量不需要被序列化,便可添加该特性,以节省消耗。

需要注意的是标志了[NonSerialized]特性的成员变量在反序列化的过程中,.Net Framework的序列化API并不会初始化它们。同时,由于反序列化的时候类的构造函数不会被调用,所以成员的初始化器也就不会被执行。这将导致这些成员将被初始化为初始值0。

为了避免此种弊端,可以实现IDeserializationCallback接口的OnDeserialization()方法来初始化被添加了[NonSerialized]特性的成员,这个方法会在整个对象被反序列化完成之后调用。然而,在OnDeserialization()执行完成之前,该实例的所有公共成员就可以被外部访问,如果此时OnDeserialization()还未执行完毕,外部访问的就是一个还未初始化完成的成员(多线程下可能会发生此情况)。

蠢逼地絮絮叨叨:如果是使用构造函数new出来的对象,当然就不会有这种情况。毕竟在构造函数完成之前,其他逻辑是无法获取并访问到该对象以及它的任何一个成员的。

(其他待续)

28 提供粗粒度的因特网服务API

其实就是说尽量减少频繁的网络操作。尽量把多个Http请求集合成一个,减少一来一回的时间消耗。

29 支持泛型协变和逆变

??? 我感觉不是很实用?再说吧。

Buy Me A Coffee / 捐一杯咖啡的钱
分享这篇文章~
0%
//