• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C#模板编程(2):编写C#预处理器,让模板来的再自然一点

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

一、C#预处理机制设计

问题的关键就是在C#的源文件中引入include机制,设计下面的语法:

(1) 引入:#region include <path> #endregion

(2) 被引:#region mixin … #endgion

 

例子:假设A.cs需要引用B.cs中的代码。A文件内容为:

XXX

#region include "B.cs"
#endregion

XXX

B.cs 文件内容为:

YYY

#region mixin

MMM

#endregion

ZZZ

运行预处理器,对A文件进行处理,生成第三个文件A_.cs:

XXX

MMM

XXX

二、实现

编写预处理器:Csmacro.exe[Csmacro.zip](意思是CSharp Macro)程序,代码如下:

Csmacro
  1 using System;
  2 using System.Collections.Generic;
  3 using System.IO;
  4 using System.Text;
  5 using System.Text.RegularExpressions; 
  6 
  7 namespace Orc.Util.Csmacro
  8 {
  9     class Program
 10     {
 11         static Regex includeReg = new Regex("#region\\s+include.+\\s+#endregion");
 12         static Regex mixinReg = new Regex("(?<=#region\\s+mixin\\s)[\\s|\\S]+(?=#endregion)"); 
 13 
 14         /// <summary>
 15         /// Csmacro [dir|filePath]
 16         /// 
 17         /// 语法:
 18         ///     #region include ""
 19         ///     #endregion
 20         ///     
 21         /// </summary>
 22         /// <param name="args"></param>
 23         static void Main(string[] args)
 24         {
 25             if (args.Length != 1)
 26             {
 27                 PrintHelp();
 28                 return;
 29             } 
 30 
 31             String filePath = args[0]; 
 32 
 33             Path.GetDirectoryName(filePath);
 34             String dirName = Path.GetDirectoryName(filePath);
 35 #if DEBUG
 36             Console.WriteLine("dir:" + dirName);
 37 #endif
 38             String fileName = Path.GetFileName(filePath);
 39 #if DEBUG
 40             Console.WriteLine("file:" + fileName);
 41 #endif 
 42 
 43             if (String.IsNullOrEmpty(fileName))
 44             {
 45                 Csmacro(new DirectoryInfo(dirName));
 46             }
 47             else
 48             {
 49                 if (fileName.EndsWith(".cs"== false)
 50                 {
 51                     Console.WriteLine("Csmacro只能处理后缀为.cs的源程序.");
 52                 }
 53                 else
 54                 {
 55                     Csmacro(new FileInfo(fileName));
 56                 }
 57             } 
 58 
 59             Console.WriteLine("[Csmacro]:处理完毕."); 
 60 
 61 #if DEBUG
 62             Console.ReadKey();
 63 #endif
 64         } 
 65 
 66         static void Csmacro(DirectoryInfo di)
 67         {
 68             Console.WriteLine("[Csmacro]:进入目录" + di.FullName); 
 69 
 70             foreach (FileInfo fi in di.GetFiles("*.cs", SearchOption.AllDirectories))
 71             {
 72                 Csmacro(fi);
 73             }
 74         } 
 75 
 76         static void Csmacro(FileInfo fi)
 77         {
 78             String fullName = fi.FullName;
 79             if (fi.Exists == false)
 80             {
 81                 Console.WriteLine("[Csmacro]:文件不存在-" + fullName);
 82             }
 83             else if (fullName.EndsWith("_Csmacro.cs"))
 84             {
 85                 return;
 86             }
 87             else
 88             {
 89                 String text = File.ReadAllText(fullName); 
 90 
 91                 DirectoryInfo parrentDirInfo = fi.Directory; 
 92 
 93                 MatchCollection mc = includeReg.Matches(text);
 94                 if (mc == null || mc.Count == 0return;
 95                 else
 96                 {
 97                     Console.WriteLine("[Csmacro]:处理文件" + fullName); 
 98 
 99                     StringBuilder sb = new StringBuilder();
100                     Match first = mc[0];
101                     Match last = mc[mc.Count - 1]; 
102 
103                     sb.Append(text.Substring(0, first.Index)); 
104 
105                     foreach (Match m in mc)
106                     {
107                         String tmp = Csmacro(parrentDirInfo, m.Value);
108                         sb.Append(tmp);
109                     } 
110 
111                     Int32 lastEnd = last.Index + last.Length;
112                     if (lastEnd < text.Length)
113                     {
114                         sb.Append(text.Substring(lastEnd));
115                     }
116                     String newName = fullName.Substring(0, fullName.Length - 3+ "_Csmacro.cs";
117                     if (File.Exists(newName))
118                     {
119                         Console.WriteLine("[Csmacro]:删除旧文件" + newName);
120                     }
121                     File.WriteAllText(newName, sb.ToString());
122                     Console.WriteLine("[Csmacro]:生成文件" + newName);
123                 }
124             }
125         } 
126 
127         static String Csmacro(DirectoryInfo currentDirInfo, String text)
128         {
129             String outfilePath = text.Replace("#region", String.Empty).Replace("#endregion", String.Empty).Replace("include",String.Empty).Replace("\"",String.Empty).Trim();
130             try
131             {
132                 if (Path.IsPathRooted(outfilePath) == false)
133                 {
134                     outfilePath = currentDirInfo.FullName + @"\" + outfilePath;
135                 }
136                 FileInfo fi = new FileInfo(outfilePath);
137                 if (fi.Exists == false)
138                 {
139                     Console.WriteLine("[Csmacro]:文件" + fi.FullName + "不存在.");
140                     return text;
141                 }
142                 else
143                 {
144                     return GetMixinCode(File.ReadAllText(fi.FullName));
145                 }
146             }
147             catch (Exception ex)
148             {
149                 Console.WriteLine("[Csmacro]:出现错误(" + outfilePath + ")-" + ex.Message);
150             }
151             finally
152             {
153             }
154             return text;
155         } 
156 
157         static String GetMixinCode(String txt)
158         {
159             Match m = mixinReg.Match(txt);
160             if (m.Success == true)
161             {
162                 return m.Value;
163             }
164             else return String.Empty;
165         } 
166 
167         static void PrintHelp()
168         {
169             Console.WriteLine("Csmacro [dir|filePath]");
170         }
171     }
172 }
173 
174 

 

编译之后,放在系统路径下(或放入任一在系统路径下的目录)。然后,在VS的项目属性的Build Events的Pre-build event command line中写入“Csmacro.exe $(ProjectDir)”,即可在编译项目之前,对$(ProjectDir)目录下的所有cs程序进行预处理。

Csmacro.exe 对于包含#region include <path> #endregion代码的程序xx.cs,预处理生成名为 xx_Csmacro.cs的文件;对于文件名以"Csmacro.cs”结尾的文件,则不进行任何处理。

使用时要注意:

(1)#region include <path> 与 #endregion 之间不能有任何代码;

(2)#region mixin 与 #endgion 之间不能有其它的region

(3)不支持多级引用

三、示例

下面,以《C#模板编程(1):有了泛型,为什么还需要模板?》文尾的例子说明怎样编写C#模板程序:

(1)建立一个模板类 FilterHelper_Template.cs ,编译通过:

FilterHelper_Template.cs
 1 using TPixel = System.Byte; 
 2 using TCache = System.Int32; 
 3 using TKernel = System.Int32; 
 4 
 5 using System; 
 6 using System.Collections.Generic; 
 7 using System.Text; 
 8 
 9 namespace Orc.SmartImage.Hidden 
10 
11     static class FilterHelper_Template 
12     { 
13         #region mixin 
14 
15         // 本算法是错误的,只为说明C#模板程序的使用。 
16         public unsafe static UnmanagedImage<TPixel> Filter(this UnmanagedImage<TPixel> src, FilterKernel<TKernel> filter) 
17         { 
18             TKernel* kernel = stackalloc TKernel[filter.Length]; 
19 
20             Int32 srcWidth = src.Width; 
21             Int32 srcHeight = src.Height; 
22             Int32 kWidth = filter.Width; 
23             Int32 kHeight = filter.Height; 
24 
25             TPixel* start = (TPixel*)src.StartIntPtr; 
26             TPixel* lineStart = start; 
27             TPixel* pStart = start; 
28             TPixel* pTemStart = pStart; 
29             TPixel* pT; 
30             TKernel* pK; 
31 
32             for (int c = 0; c < srcWidth; c++
33             { 
34                 for (int r = 0; r < srcHeight; r++
35                 { 
36                     pTemStart = pStart; 
37                     pK = kernel; 
38 
39                     Int32 val = 0
40                     for (int kc = 0; kc < kWidth; kc++
41                     { 
42                         pT = pStart; 
43                         for (int kr = 0; kr < kHeight; kr++
44                         { 
45                             val += *pK * *pT; 
46                             pT++
47                             pK++
48                         } 
49 
50                         pStart += srcWidth; 
51                     } 
52 
53                     pStart = pTemStart; 
54                     pStart++
55                 } 
56 
57                 lineStart += srcWidth; 
58                 pStart = lineStart; 
59             } 
60             return null
61         } 
62         #endregion 
63     } 
64 }
65 
66 

 这里,我使用了命名空间Hidden,意思是这个命名空间不想让外部使用,因为它是模板类。

 

(2)编写实例化模板类 ImageU8FilterHelper.cs

ImageU8FilterHelper.cs
 1 using System; 
 2 using System.Collections.Generic; 
 3 

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
C# wpf 使用资源文件 resx发布时间:2022-07-14
下一篇:
C#WinFormDataGridView给标题列增加序号及格式化某个字段发布时间:2022-07-14
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap