本文是我博客的镜像,原文地址是:
系列文章引言
众所周知,我是个彻彻底底的C#控,但是没有东西是完美的,C#也是一样,所以在这里我就yy一下,设想一下我心中C#将来的样子,故取名为《C#狂想曲》系列。测试程序
为了体现对C#的变化,我设定了一份游戏编程中经常遇到的程序作为标准来体现变化。
2 using System.Collections.Generic;
3
4 namespace Orandea.Webgame
5 {
6 public class Player
7 {
8 public int Id { get; set; }
9 public int UserId { get; set; }
10 public string Name { get; set; }
11 }
12
13 public interface IPlayerService
14 {
15 int CreatePlayer(int userId, string name);
16 Player GetPlayer(int playerId);
17 Player GetPlayer(string name);
18 Player GetUserPlayer(int userId);
19 }
20
21 public class PlayerService : IPlayerService
22 {
23 public int CreatePlayer(int userId, string name)
24 {
25 var player = new Player
26 {
27 Id = _playerIndex++,
28 UserId = userId,
29 Name = name;
30 };
31
32 _players.Add(player);
33
34 return player.Id;
35 }
36
37 public Player GetPlayer(int playerId)
38 {
39 return _players.FirstOrDefault(p => p.Id == playerId);
40 }
41
42 public Player GetPlayer(string playerName)
43 {
44 return _players.FirstOrDefault(p => p.Name == playerName);
45 }
46
47 public Player GetUserPlayer(int userId)
48 {
49 return _players.FirstOrDefault(p => p.UserId == userId);
50 }
51
52 private int _playerIndex = 0;
53 private List<Player> _players = new List<Player>();
54 }
55 }
很简单的程序,然后显然这是一个线程不安全的程序,线程安全的版本,我们回头再说。
去类型化
C#是一个强类型语言,相对来说也是一个静态语言。然而现在的程序越来越灵活,C#的静态性已经开始逐步制约了创造力的发挥。在处理Web场景和游戏场景中已经变的越来越力不从心,所以,在这里提出一个去类型化的想法:
类似JavaScript,申明变量、声明函数时,不需要声明类型。则上述程序变成
2 using System.Collections.Generic;
3
4 namespace Orandea.Webgame
5 {
6 public class Player
7 {
8 public var Id { get; set; }
9 public var UserId { get; set; }
10 public var Name { get; set; }
11 }
12
13 public interface IPlayerService
14 {
15 function CreatePlayer(userId, name);
16 function GetPlayer(playerId);
17 function GetPlayer(name);
18 function GetUserPlayer(userId);
19 }
20
21 public class PlayerService : IPlayerService
22 {
23 public function CreatePlayer(userId, name)
24 {
25 var player = new Player
26 {
27 Id = _playerIndex++,
28 UserId = userId,
29 Name = name;
30 };
31
32 _players.Add(player);
33
34 return player.Id;
35 }
36
37 public function GetPlayer(playerId)
38 {
39 return _players.FirstOrDefault(p => p.Id == playerId);
40 }
41
42 public function GetPlayer(playerName)
43 {
44 return _players.FirstOrDefault(p => p.Name == playerName);
45 }
46
47 public function GetUserPlayer(userId)
48 {
49 return _players.FirstOrDefault(p => p.UserId == userId);
50 }
51
52 private var _playerIndex = 0;
53 private var _players = new List<Player>();
54 }
55 }
然而这会带来一个问题,就是两个GetPlayer的签名重复了,所以我们暂时取消C#的重载功能,变成这样:
2 using System.Collections.Generic;
3
4 namespace Orandea.Webgame
5 {
6 public class Player
7 {
8 public var Id { get; set; }
9 public var UserId { get; set; }
10 public var Name { get; set; }
11 }
12
13 public interface IPlayerService
14 {
15 function CreatePlayer(userId, name);
16 function GetPlayer(playerId);
17 function GetPlayerByName(name);
18 function GetUserPlayer(userId);
19 }
20
21 public class PlayerService : IPlayerService
22 {
23 public function CreatePlayer(userId, name)
24 {
25 var player = new Player
26 {
27 Id = _playerIndex++,
28 UserId = userId,
29 Name = name;
30 };
31
32 _players.Add(player);
33
34 return player.Id;
35 }
36
37 public function GetPlayer(playerId)
38 {
39 return _players.FirstOrDefault(p => p.Id == playerId);
40 }
41
42 public function GetPlayerByName(playerName)
43 {
44 return _players.FirstOrDefault(p => p.Name == playerName);
45 }
46
47 public function GetUserPlayer(userId)
48 {
49 return _players.FirstOrDefault(p => p.UserId == userId);
50 }
51
52 private var _playerIndex = 0;
53 private var _players = new List<Player>();
54 }
55 }
既然类型都不重要了,那么泛型也没有存在的必要了,去除泛型,变成这样:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 {
6 public class Player
7 {
8 public var Id { get; set; }
9 public var UserId { get; set; }
10 public var Name { get; set; }
11 }
12
13 public interface IPlayerService
14 {
15 function CreatePlayer(userId, name);
16 function GetPlayer(playerId);
17 function GetPlayerByName(name);
18 function GetUserPlayer(userId);
19 }
20
21 public class PlayerService : IPlayerService
22 {
23 public function CreatePlayer(userId, name)
24 {
25 var player = new Player
26 {
27 Id = _playerIndex++,
28 UserId = userId,
29 Name = name;
30 };
31
32 _players.Add(player);
33
34 return player.Id;
35 }
36
37 public function GetPlayer(playerId)
38 {
39 return _players.FirstOrDefault(p => p.Id == playerId);
40 }
41
42 public function GetPlayerByName(playerName)
43 {
44 return _players.FirstOrDefault(p => p.Name == playerName);
45 }
46
47 public function GetUserPlayer(userId)
48 {
49 return _players.FirstOrDefault(p => p.UserId == userId);
50 }
51
52 private var _playerIndex = 0;
53 private var _players = new List();
54 }
55 }
如果类型不重要了,那么什么重要呢?当然是通讯的接口重要。
所以我们没有必要继续显式的声明接口以及entity类了,把程序编程这样:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 {
6 public class PlayerService
7 {
8 public function CreatePlayer(userId, name)
9 {
10 var player = {
11 Id = _playerIndex++,
12 UserId = userId,
13 Name = name
14 };
15
16 _players.Add(player);
17
18 return player.Id;
19 }
20
21 public function GetPlayer(playerId)
22 {
23 return _players.FirstOrDefault(p => p.Id == playerId);
24 }
25
26 public function GetPlayerByName(playerName)
27 {
28 return _players.FirstOrDefault(p => p.Name == playerName);
29 }
30
31 public function GetUserPlayer(userId)
32 {
33 return _players.FirstOrDefault(p => p.UserId == userId);
34 }
35
36 private var _playerIndex = 0;
37 private var _players = new List();
38 }
39 }
既然取消了明确的entity声明,那么就把创建entity对象的形式变成和javascript兼容的形式把:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 {
6 public class PlayerService
7 {
8 public function CreatePlayer(userId, name)
9 {
10 var player = {
11 Id: _playerIndex++,
12 UserId: userId,
13 Name: name
14 };
15
16 _players.Add(player);
17
18 return player.Id;
19 }
20
21 public function GetPlayer(playerId)
22 {
23 return _players.FirstOrDefault(p => p.Id == playerId);
24 }
25
26 public function GetPlayerByName(playerName)
27 {
28 return _players.FirstOrDefault(p => p.Name == playerName);
29 }
30
31 public function GetUserPlayer(userId)
32 {
33 return _players.FirstOrDefault(p => p.UserId == userId);
34 }
35
36 private var _playerIndex = 0;
37 private var _players = new List();
38 }
39 }
至此,C#已经不具有编译时强类型了。继续我们的改造~~~
弱化语法
C#从C/C++中继承了很多格式化的,教条的语法,就算我们改成了javascript的形式,我们仍然需要使用var和function来显式的区分函数和变量。
在javascript中,这个限制来源于function作为第一类对象,可以在任何地方声明,如果不限制的话,会导致程序混淆。
然而在c#里面,函数作为类的成员存在,所以没有这个问题,自然的,也不需要使用function和var关键字来区分类的方法和类的数据成员,那么可以变成这样:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 {
6 public class PlayerService
7 {
8 public CreatePlayer(userId, name)
9 {
10 var player = {
11 Id: _playerIndex++,
12 UserId: userId,
13 Name: name
14 };
15
16 _players.Add(player);
17
18 return player.Id;
19 }
20
21 public GetPlayer(playerId)
22 {
23 return _players.FirstOrDefault(p => p.Id == playerId);
24 }
25
26 public GetPlayerByName(playerName)
27 {
28 return _players.FirstOrDefault(p => p.Name == playerName);
29 }
30
31 public GetUserPlayer(userId)
32 {
33 return _players.FirstOrDefault(p => p.UserId == userId);
34 }
35
36 private _playerIndex = 0;
37 private _players = new List();
38 }
39 }
在使用new关键字调用无参的构造函数的时候,那一对()是多余的,所以我们可以去掉他们:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 {
6 public class PlayerService
7 {
8 public CreatePlayer(userId, name)
9 {
10 var player = {
11 Id: _playerIndex++,
12 UserId: userId,
13 Name: name
14 };
15
16 _players.Add(player);
17
18 return player.Id;
19 }
20
21 public GetPlayer(playerId)
22 {
23 return _players.FirstOrDefault(p => p.Id == playerId);
24 }
25
26 public GetPlayerByName(playerName)
27 {
28 return _players.FirstOrDefault(p => p.Name == playerName);
29 }
30
31 public GetUserPlayer(userId)
32 {
33 return _players.FirstOrDefault(p => p.UserId == userId);
34 }
35
36 private _playerIndex = 0;
37 private _players = new List;
38 }
39 }
我想,在一个文件里面,层层相套的花括号已经太让人心烦了,所以,我们可以去掉不必要的花括号,包括namespace、class和function的,如果他们都只包含一个他们的子元素,那么可以不写花括号:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 public class PlayerService
6 {
7 public CreatePlayer(userId, name)
8 {
9 var player = {
10 Id: _playerIndex++,
11 UserId: userId,
12 Name: name
13 };
14
15 _players.Add(player);
16
17 return player.Id;
18 }
19
20 public GetPlayer(playerId)
21 return _players.FirstOrDefault(p => p.Id == playerId);
22
23 public GetPlayerByName(playerName)
24 return _players.FirstOrDefault(p => p.Name == playerName);
25
26 public GetUserPlayer(userId)
27 return _players.FirstOrDefault(p => p.UserId == userId);
28
29 private _playerIndex = 0;
30 private _players = new List;
31 }
既然lambda的语法如此的简介优美,那么我们为什么不使用lambda的语法来写method呢?
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 public class PlayerService
6 {
7 public CreatePlayer(userId, name) =>
8 {
9 var player = {
10 Id: _playerIndex++,
11 UserId: userId,
12 Name: name
13 };
14
15 _players.Add(player);
16
17 return player.Id;
18 }
19
20 public GetPlayer(playerId) => _players.FirstOrDefault(p => p.Id == playerId);
21 public GetPlayerByName(playerName) => _players.FirstOrDefault(p => p.Name == playerName);
22 public GetUserPlayer(userId) => _players.FirstOrDefault(p => p.UserId == userId);
23
24 private _playerIndex = 0;
25 private _players = new List;
26 }
哦,天哪,原来c#还可以这么简洁
加上Pattern Match
现在没有了重载,真是举步维艰啊,写程序真是太麻烦了。但是,别着急,之所以取消了重载这个非常好用的功能,是因为我们要加上一个比重载还要好用的功能:模式匹配:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 public class PlayerService
6 {
7 public CreatePlayer(userId, name)
8 {
9 var player = {
10 Id: _playerIndex++,
11 UserId: userId,
12 Name: name
13 };
14
15 _players.Add(player);
16
17 return player.Id;
18 }
19
20 public GetPlayer("playerId", playerId) => _players.FirstOrDefault(p => p.Id == playerId);
21 public GetPlayer("playerName", playerName) => _players.FirstOrDefault(p => p.Name == playerName);
22 public GetPlayer("userId", userId) => _players.FirstOrDefault(p => p.UserId == userId);
23
24 private _playerIndex = 0;
25 private _players = new List;
26 }
哇,这样的c#好美啊。
使用C++式的访问控制描述符形式
C#的方式确实挺好的,但是,这样容易让人把public的和private的东西交错放置,这就太乱了,所以使用C++形式的访问控制描述符吧:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 public class PlayerService
6 {
7 public:
8 CreatePlayer(userId, name)
9 {
10 var player = {
11 Id: _playerIndex++,
12 UserId: userId,
13 Name: name
14 };
15
16 _players.Add(player);
17
18 return player.Id;
19 }
20
21 GetPlayer("playerId", playerId) => _players.FirstOrDefault(p => p.Id == playerId);
22 GetPlayer("playerName", playerName) => _players.FirstOrDefault(p => p.Name == playerName);
23 GetPlayer("userId", userId) => _players.FirstOrDefault(p => p.UserId == userId);
24
25 private:
26 _playerIndex = 0;
27 _players = new List;
28 }
哇,这真的好清晰,好美啊
加上动态属性吧
神马?那indexer情何以堪?好吧,那就先忘记indexer吧,把我们亲爱的动态属性先弄到再说:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 public class PlayerService
6 {
7 public:
8 CreatePlayer(userId, name)
9 {
10 var player = {
11 Id: _playerIndex++,
12 UserId: userId,
13 Name: name
14 };
15
16 _players.Add(player);
17
18 return player.Id;
19 }
20
21 GetPlayer(field, playerId) => _players.FirstOrDefault(p => p[field] == playerId);
22
23 private:
24 _playerIndex = 0;
25 _players = new List;
26 }
加上Guard吧
万一有人不怀好意,使用其他ws的参数来攻击怎么办?加上Guard吧:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 public class PlayerService
6 {
7 public:
8 CreatePlayer(userId, name)
9 {
10 var player = {
11 Id: _playerIndex++,
12 UserId: userId,
13 Name: name
14 };
15
16 _players.Add(player);
17
18 return player.Id;
19 }
20
21 GetPlayer(field, playerId)
22 when (field == "Id" || field == "UserId" || field == "Name")
23 => _players.FirstOrDefault(p => p[field] == playerId);
24
25 private:
26 _playerIndex = 0;
27 _players = new List;
28 }
加上in关键字吧
哦,天哪,这太丑陋了,就不能弄个好看点的东西?
唔~~~那就加上in关键字吧:
2 using System.Collections;
3
4 namespace Orandea.Webgame
5 public class PlayerService
6 {
7 public:
8 CreatePlayer(userId, name)
9 {
10 var player = {
11 Id: _playerIndex++,
12 UserId: userId,
13 Name: name
14 };
15
16 _players.Add(player);
17
18 return player.Id;
19 }
20
21 GetPlayer(field, playerId)
22 when (field in ["Id", "UserId", "Name"])
23 => _players.FirstOrDefault(p => p[field] == playerId);
24
25 private:
26 _playerIndex = 0;
27 _players = new List;
28 }
恩,今天就先到这里吧,到下一节,我们加上一些消息通讯的东西,瓦咔咔