C#编程模式之扩展命令

简介:

C#编程模式之扩展命令

前言

根据上一篇的命令模式和在工作中遇到的一些实际情况,有了本篇文章,时时都是学习的一个过程,会在这个过程中发现许多好的模式或者是一种开发方式,今天写出来的就是我工作中常用到的,自己感觉这种方式很优雅很漂亮,就自己试着实现了一下,可能原框架中不是这样的,有许多不足之处还请大家指点。

 

需求

我还不清楚这种方式是模式还是框架开发中用到的技术,我暂且叫它为命令控制器吧。

命令控制器的主要功能就是获取用户提供的命令,然后来执行命令。 在这里我把要执行的“命令”设计成一个函数,会对应着一个String类型的命令字符串,并且命令控制器是允许扩展的。

 

实现
首先我定义了一个属性类,用于在扩展的命令类、或者命令函数上,只有一个CommandName属性,作用于命令函数上的话,则代表命令名称,如果是作用于类上面的话就代表命令类别的名称,只是考虑可以作为一个分类,这部分在后面有讲到,可以自定义实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1      /// <summary>
2      /// 命令所用代码属性类
3      /// </summary>
4     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple =  false , Inherited =  true )]
5      public  class  CommandAttribute : Attribute
6     {
7          private  string  commandName =  null ;
8
9          public  string  CommandName
10         {
11              get  return  commandName; }
12              set  { commandName = value; }
13         }
14
15          public  CommandAttribute( string  CommandName)
16         {
17             commandName = CommandName;
18         }
19     }

有了这个属性类了,我们就要把它用起来,定义一些后面要用到的命令示例类,


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
27
28
29
30
31
32
33
34
35
36
37
1      /// <summary>
2      /// 示例:命令类以及命令函数,亦可当作为扩展
3      /// </summary>
4     [Command( "Test" )]
5      public  class  CommandTest : CommandMethod
6     {
7         [Command( "MyCommandone" )]
8          public  object  test(ICommandParameter commandparameter)
9         {
10              return  null ;
11         }
12
13         [Command( "MyCommandone1" )]
14          public  object  test1(ICommandParameter commandparameter)
15         {
16              return  null ;
17         }
18
19         [Command( "MyCommandone2" )]
20          public  object  test2(ICommandParameter commandparameter)
21         {
22              return  null ;
23         }
24
25
26         [Command( "MyCommandone3" )]
27          public  object  test3(ICommandParameter commandparameter)
28         {
29              return  null ;
30         }
31
32         [Command( "MyCommandone4" )]
33          public  object  test4(ICommandParameter commandparameter)
34         {
35              return  null ;
36         }
37     }

上面的示例代码中可以看到CommandTest类继承自CommandMethod类,而类里面的一些函数的签名也是一样的,函数参数都为ICommandParameter接口类型,这就是扩展命令方法时要遵循的一些规范,定义的规范:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1      /// <summary>
2      /// 扩展命令函数的参数规范
3      /// </summary>
4      public  interface  ICommandParameter
5     {
6
7     }
8
9      /// <summary>
10      /// 扩展命令方法类基类
11      /// </summary>
12      public  class  CommandMethod
13     {
14
15     }

需要实现什么都是可以自定义,比如说可以在ICommandParameter接口中定义个object类型的名称为ContainerObject的属性,意思就是容器属性,可以在后面调用命令时,传入实例参数时设置容器属性的值,可以设置为任何你想设置的值到里面,然后再在命令函数里使用它,也可以根据抽象定义实现一个参数上下文对象专门用于处理扩展命令的,看需要自定义吧。

然后就是书写一个命令控制器的代码了,它呢主要负责把客户端注册进来的类型做一些处理,比如说 判断类型、反射类型获取函数命令以及函数信息、把命令函数转换成委托、维护命令列表等等一些简单的功能,还用到了一个CommandMethodActionDelegate类型的委托:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
1      public  delegate  object  CommandMethodActionDelegate(ICommandParameter commandParameter);
2
3      public  class  CommandController
4     {
5          private  static  CommandController _Instance =  null ;
6
7          public  static  CommandController Instance
8         {
9              get
10             {
11                  if  (_Instance ==  null )
12                 {
13                     _Instance =  new  CommandController(HostDevelopment.Instance);
14                 }
15                  return  _Instance;
16             }
17         }
18
19          private  HostDevelopment _CommandDevelopment = HostDevelopment.Instance;
20
21          public  CommandController(HostDevelopment commandDevelopment)
22         {
23             _CommandDevelopment = commandDevelopment;
24         }
25
26          private  Dictionary< string , CommandMethodActionDelegate> commandlist =  new  Dictionary< string , CommandMethodActionDelegate>();
27
28
29          private  List< string > _commandNames =  null ;
30          /// <summary>
31          /// 命令名称集合
32          /// </summary>
33          public  List< string > CommandNames
34         {
35              get
36             {
37                  if  (_commandNames ==  null )
38                 {
39                     GetCommandNames();
40                 }
41                  return  _commandNames;
42             }
43         }
44
45          private  void  GetCommandNames()
46         {
47
48              if  (commandlist.Count > 0)
49             {
50                  if  (_commandNames ==  null )
51                 {
52                     _commandNames =  new  List< string >();
53                 }
54                  foreach  ( string  name  in  commandlist.Keys)
55                 {
56                     _commandNames.Add(name);
57                 }
58             }
59         }
60
61          public  bool  RegisterCommand( object  instance)
62         {
63             Type t = instance.GetType();
64             CommandAttribute cmdatt = (CommandAttribute)Attribute.GetCustomAttribute(t,  typeof (CommandAttribute),  false );
65              if  (cmdatt !=  null )
66             {
67                 AddCommandToModel(instance);
68                  return  true ;
69             }
70              else  return  false ; }
71         }
72
73          private  void  AddCommandToModel( object  instance)
74         {
75             Type t = instance.GetType();
76             MethodInfo[] methods = t.GetMethods();
77              foreach  (MethodInfo methodinfo  in  methods)
78             {
79                 CommandAttribute cmdatt = (CommandAttribute)Attribute.GetCustomAttribute(methodinfo,  typeof (CommandAttribute),  false );
80                  if  (cmdatt !=  null )
81                 {
82
83                     CommandMethodActionDelegate commanddelegate = (CommandMethodActionDelegate)Delegate.CreateDelegate( typeof (CommandMethodActionDelegate), instance, methodinfo.Name);
84                     commandlist.Add(cmdatt.CommandName, commanddelegate);
85                 }
86
87             }
88         }
89
90
91          internal  object  Execute( string  commandName, ICommandParameter commandParameter)
92         {
93              if  (commandName ==  null )
94             {
95                  throw  new  ArgumentNullException( "commandName" );
96             }
97              if  (!commandlist.ContainsKey(commandName))
98             {
99                  return  new  ArgumentNullException( "不包含的命令,命令无效" );
100             }
101             CommandMethodActionDelegate cmdaction = commandlist[commandName];
102              return  cmdaction.Invoke(commandParameter);
103         }
104     }
在CommandController类型中,RegisterCommand()方法为注册扩展命令到命令控制器,示例中的注册方式为手动的传入类型实例来注册的,也可以把实现方式修改为在命令控制器启动的时候获取当前系统所有依赖项的程序集,获取到所有符合类型规范的扩展命令类型,并且注册到控制器中。

上面代码中有说到的HostDevelopment类型,是我定义的一个宿主容器对象,用它来承载命令控制器,以及在这个系列的文章中,都是使用HostDevelopment来进行对控制器的承载,这是后话。现在来看一下HostDevelopment暂时的定义:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
1      public  delegate  object  CommandMethodActionDelegate(ICommandParameter commandParameter);
2
3      public  class  CommandController
4     {
5          private  static  CommandController _Instance =  null ;
6
7          public  static  CommandController Instance
8         {
9              get
10             {
11                  if  (_Instance ==  null )
12                 {
13                     _Instance =  new  CommandController(HostDevelopment.Instance);
14                 }
15                  return  _Instance;
16             }
17         }
18
19          private  HostDevelopment _CommandDevelopment = HostDevelopment.Instance;
20
21          public  CommandController(HostDevelopment commandDevelopment)
22         {
23             _CommandDevelopment = commandDevelopment;
24         }
25
26          private  Dictionary< string , CommandMethodActionDelegate> commandlist =  new  Dictionary< string , CommandMethodActionDelegate>();
27
28
29          private  List< string > _commandNames =  null ;
30          /// <summary>
31          /// 命令名称集合
32          /// </summary>
33          public  List< string > CommandNames
34         {
35              get
36             {
37                  if  (_commandNames ==  null )
38                 {
39                     GetCommandNames();
40                 }
41                  return  _commandNames;
42             }
43         }
44
45          private  void  GetCommandNames()
46         {
47
48              if  (commandlist.Count > 0)
49             {
50                  if  (_commandNames ==  null )
51                 {
52                     _commandNames =  new  List< string >();
53                 }
54                  foreach  ( string  name  in  commandlist.Keys)
55                 {
56                     _commandNames.Add(name);
57                 }
58             }
59         }
60
61          public  bool  RegisterCommand( object  instance)
62         {
63             Type t = instance.GetType();
64             CommandAttribute cmdatt = (CommandAttribute)Attribute.GetCustomAttribute(t,  typeof (CommandAttribute),  false );
65              if  (cmdatt !=  null )
66             {
67                 AddCommandToModel(instance);
68                  return  true ;
69             }
70              else  return  false ; }
71         }
72
73          private  void  AddCommandToModel( object  instance)
74         {
75             Type t = instance.GetType();
76             MethodInfo[] methods = t.GetMethods();
77              foreach  (MethodInfo methodinfo  in  methods)
78             {
79                 CommandAttribute cmdatt = (CommandAttribute)Attribute.GetCustomAttribute(methodinfo,  typeof (CommandAttribute),  false );
80                  if  (cmdatt !=  null )
81                 {
82
83                     CommandMethodActionDelegate commanddelegate = (CommandMethodActionDelegate)Delegate.CreateDelegate( typeof (CommandMethodActionDelegate), instance, methodinfo.Name);
84                     commandlist.Add(cmdatt.CommandName, commanddelegate);
85                 }
86
87             }
88         }
89
90
91          internal  object  Execute( string  commandName, ICommandParameter commandParameter)
92         {
93              if  (commandName ==  null )
94             {
95                  throw  new  ArgumentNullException( "commandName" );
96             }
97              if  (!commandlist.ContainsKey(commandName))
98             {
99                  return  new  ArgumentNullException( "不包含的命令,命令无效" );
100             }
101             CommandMethodActionDelegate cmdaction = commandlist[commandName];
102              return  cmdaction.Invoke(commandParameter);
103         }
104     }
看了这些了,应该就大致的明白了,不过现在这样的代码还是测试不了的,因为缺少一些实体。定义一个默认实现的命令参数规范:
1
2
3
4
5
6
7
8
9
10
1      public  class  CommandParameterCase:ICommandParameter
2     {
3          private  string  _StrText;
4
5          public  string  StrText
6         {
7              get  return  _StrText; }
8              set  { _StrText = value; }
9         }
10     }
然后再修改一下CommandTest类型中的第一个叫test的函数(对应的命令名称为MyCommandone),函数名称有点随意,大家不要介意这些。
1
2
3
4
5
6
7
8
9
10
1         [Command( "MyCommandone" )]
2          public  object  test(ICommandParameter commandparameter)
3         {
4              if  (commandparameter !=  null )
5             {
6                 CommandParameterCase commandparametercase = commandparameter  as  CommandParameterCase;
7                  return  commandparametercase.StrText;
8             }
9              else  return  null ; }
10         }
这样所需的都定义齐了。
我们再看一下调用代码:
1
2
3
1 HostDevelopment.Instance.Start();
2 HostDevelopment.Instance.CommandController.RegisterCommand( new  CommandTest());
var  strtext = HostDevelopment.Instance.Execute( "MyCommandone" new  CommandParameterCase() { StrText =  "test"  });
对了随便是打个断点或者是输出strtext都可以看到它的值。这里不作多的解释了。

最后加上对象关系图解吧,并不是什么标准的画法,有助于理解就行了。

111442190885653.png

 END

 

     本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1409597,如需转载请自行联系原作者







相关文章
|
2月前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
41 3
|
4天前
|
C#
基于 C# 编写的 Visual Studio 文件编码显示与修改扩展插件
基于 C# 编写的 Visual Studio 文件编码显示与修改扩展插件
|
13天前
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
57 12
|
2月前
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
68 4
|
2月前
|
C# Python
使用wxpython开发跨平台桌面应用,对wxpython控件实现类似C#扩展函数处理的探究
【10月更文挑战第30天】使用 `wxPython` 开发跨平台桌面应用时,可以通过创建辅助类来模拟 C# 扩展函数的功能。具体步骤包括:1. 创建辅助类 `WxWidgetHelpers`;2. 在该类中定义静态方法,如 `set_button_color`;3. 在应用中调用这些方法。这种方法提高了代码的可读性和可维护性,无需修改 `wxPython` 库即可为控件添加自定义功能。但需要注意显式调用方法和避免命名冲突。
|
4月前
|
设计模式 开发框架 前端开发
MVC 模式在 C# 中的应用
MVC(Model-View-Controller)模式是广泛应用于Web应用程序开发的设计模式,将应用分为模型(存储数据及逻辑)、视图(展示数据给用户)和控制器(处理用户输入并控制模型与视图交互)三部分,有助于管理复杂应用并提高代码可读性和维护性。在C#中,ASP.NET MVC框架常用于构建基于MVC模式的Web应用,通过定义模型、控制器和视图,实现结构清晰且易维护的应用程序。
68 2
|
3月前
|
设计模式 程序员 C#
C# 使用 WinForm MDI 模式管理多个子窗体程序的详细步骤
WinForm MDI 模式就像是有超能力一般,让多个子窗体井然有序地排列在一个主窗体之下,既美观又实用。不过,也要小心管理好子窗体们的生命周期哦,否则一不小心就会出现一些意想不到的小bug
257 0
|
4月前
|
API C#
C# 一分钟浅谈:文件系统编程
在软件开发中,文件系统操作至关重要。本文将带你快速掌握C#中文件系统编程的基础知识,涵盖基本概念、常见问题及解决方法。文章详细介绍了`System.IO`命名空间下的关键类库,并通过示例代码展示了路径处理、异常处理、并发访问等技巧,还提供了异步API和流压缩等高级技巧,帮助你写出更健壮的代码。
56 2
|
3月前
|
安全 C# 数据安全/隐私保护
实现C#编程文件夹加锁保护
【10月更文挑战第16天】本文介绍了两种用 C# 实现文件夹保护的方法:一是通过设置文件系统权限,阻止普通用户访问;二是使用加密技术,对文件夹中的文件进行加密,防止未授权访问。提供了示例代码和使用方法,适用于不同安全需求的场景。
159 0
|
4月前
|
安全 程序员 编译器
C#一分钟浅谈:泛型编程基础
在现代软件开发中,泛型编程是一项关键技能,它使开发者能够编写类型安全且可重用的代码。C# 自 2.0 版本起支持泛型编程,本文将从基础概念入手,逐步深入探讨 C# 中的泛型,并通过具体实例帮助理解常见问题及其解决方法。泛型通过类型参数替代具体类型,提高了代码复用性和类型安全性,减少了运行时性能开销。文章详细介绍了如何定义泛型类和方法,并讨论了常见的易错点及解决方案,帮助读者更好地掌握这一技术。
89 11