C#模板编程(1):有了泛型,为什么还需要模板?

简介:

C#泛型编程已经深入人心了。为什么又提出C#模板编程呢?因为C#泛型存在一些局限性,突破这些局限性,需要使用C#方式的模板编程。由于C#语法、编译器、IDE限制,C#模板编程没有C++模板编程使用方便,但是,仍然可以解决一些问题。

 

下面先看C#泛型编程的两个限制:

(1)类型约束问题。

C#泛型的类型约束是个很严重的问题。

假设需要写一个泛型方法,这个方法有2个参数,然后方法返回结果是这两个参数的和。

这样的泛型方法无法直接实现。因为Byte,Int32等等并没有公共接口。

没有公共接口,但又想借助泛型来节省代码,减少维护量。怎么办呢?

我之前写过2篇博客《实现.net下的动态代理》、《实现.net下的动态代理(续)-多对象Mixin》,通过Ducking Typing来实现,但这种实现方式不自然,且性能低下,只适合对性能不敏感的场景。

(2)泛型指针问题。

泛型程序中无法使用泛型指针,因为编译器编译时无法知道具体类型的Size,这对写unsafe代码是很大的限制。

 

因此,我们需要C#模板编程。C#模板编程说起来很简单,它借助的是C#的一个语法——Using T0=T1。它没有C++那么自然,因为它缺乏C/C++源文件的Include机制。你可以将整块的文件在不同的类之间进行复制和粘帖。虽然复制和粘帖是一大邪恶,但总比复制/粘帖/替换要好很多。

下面是C#模板编程的一个重要应用——图像处理的空间线性滤波。关于空间线性滤波可参见各种图像处理的书,这里不做介绍。

我们假定图像是一个泛型类Image<T0>,这里T代表每一个像素的存储类型。可以是Byte,Short,Int32,Int64,Single,Double等。然后,核是一个泛型类,Kernel<T1>,这里还有第三个泛型类,就是用于存放中间数据的Image<T2>。为什么需要T2呢?假如T0是Byte,T1是带有Scale的Int32(如,Scale=9,每个元素值=1的3*3矩阵),计算的中间结果会超出Byte的最大值,需要一个不同类型缓存来存储这个中间数据。

只用泛型的话,解决不了这个问题。第一点,Byte,Short,Int32,Int64,Single,Double之间未实现共同接口;第二点,为提升性能,Image<T>采用非托管内存实现,使用指针进行操作,而泛型中无法使用泛型指针。

使用C#模板可以解决这个问题——代码照旧,只是在头部写下:Using T0=XXX;Using T1=XXX;Using T2=XXX;即可。

由于欠缺源代码的Include机制,当要编写新的滤波器时,需要把相同的代码复制过去,然后更改头部的Using ……。但无论如何,这样使用,还是比在代码中直接写明类型,然后复制、粘帖、替换新类型的可读性以及可维护性要好。

如果.Net允许源代码的Include,C#的模板编程将变得更为流畅(比起C++还是欠缺很多)。不知道等后续.Net版本开放编译服务之后,会不会有更优雅的写法。

下面是我随便写下的一段对图像进行空间线性滤波的代码(不要看具体算法,具体算法是极端错误的,且不完整的,只用看看编码风格就行了,写这段代码只为验证这种编程模式的优点和缺点):

using System; 
using System.Collections.Generic; 
using System.Text;

using T = System.Byte; 
using CacheT = System.Int32; 
using K = System.Int32;

namespace Orc.SmartImage.UnmanagedImage 

    public static class FilterHelper 
    { 
        public unsafe static UnmanagedImage<T> Filter(this UnmanagedImage<T> src, FilterKernel<K> filter) 
        { 
            K* kernel = stackalloc K[filter.Length];

            Int32 srcWidth = src.Width; 
            Int32 srcHeight = src.Height; 
            Int32 kWidth = filter.Width; 
            Int32 kHeight = filter.Height;

            T* start = (T*) src.StartIntPtr; 
            T* lineStart = start; 
            T* pStart = start; 
            T* pTemStart = pStart; 
            T* pT; 
            Int32* pK;

            for (int c = 0; c < srcWidth; c++) 
            { 
                for (int r = 0; r < srcHeight; r++) 
                { 
                    pTemStart = pStart; 
                    pK = kernel;

                    Int32 val = 0; 
                    for (int kc = 0; kc < kWidth; kc++) 
                    { 
                        pT = pStart; 
                        for (int kr = 0; kr < kHeight; kr++) 
                        { 
                            val += *pK * *pT; 
                            pT++; 
                            pK++; 
                        }

                        pStart += srcWidth; 
                    }

                    pStart = pTemStart; 
                    pStart++; 
                }

                lineStart += srcWidth; 
                pStart = lineStart; 
            } 
            return null; 
        } 
    } 
}

 

是不是很像模板编程呢?

本文转自xiaotie博客园博客,原文链接http://www.cnblogs.com/xiaotie/archive/2010/03/22/1691705.html如需转载请自行联系原作者


xiaotie 集异璧实验室(GEBLAB)

相关文章
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
622 3
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。
457 3
|
7月前
|
XML 前端开发 C#
C#编程实践:解析HTML文档并执行元素匹配
通过上述步骤,可以在C#中有效地解析HTML文档并执行元素匹配。HtmlAgilityPack提供了一个强大而灵活的工具集,可以处理各种HTML解析任务。
340 19
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
383 3
|
8月前
|
监控 算法 C#
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
1685 0
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
1302 12
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
664 4
|
安全 程序员 编译器
C#一分钟浅谈:泛型编程基础
在现代软件开发中,泛型编程是一项关键技能,它使开发者能够编写类型安全且可重用的代码。C# 自 2.0 版本起支持泛型编程,本文将从基础概念入手,逐步深入探讨 C# 中的泛型,并通过具体实例帮助理解常见问题及其解决方法。泛型通过类型参数替代具体类型,提高了代码复用性和类型安全性,减少了运行时性能开销。文章详细介绍了如何定义泛型类和方法,并讨论了常见的易错点及解决方案,帮助读者更好地掌握这一技术。
341 11
|
API C#
C# 一分钟浅谈:文件系统编程
在软件开发中,文件系统操作至关重要。本文将带你快速掌握C#中文件系统编程的基础知识,涵盖基本概念、常见问题及解决方法。文章详细介绍了`System.IO`命名空间下的关键类库,并通过示例代码展示了路径处理、异常处理、并发访问等技巧,还提供了异步API和流压缩等高级技巧,帮助你写出更健壮的代码。
228 2
|
SQL 开发框架 安全
并发集合与任务并行库:C#中的高效编程实践
在现代软件开发中,多核处理器普及使多线程编程成为提升性能的关键。然而,传统同步模型在高并发下易引发死锁等问题。为此,.NET Framework引入了任务并行库(TPL)和并发集合,简化并发编程并增强代码可维护性。并发集合允许多线程安全访问,如`ConcurrentQueue&lt;T&gt;`和`ConcurrentDictionary&lt;TKey, TValue&gt;`,有效避免数据不一致。TPL则通过`Task`类实现异步操作,提高开发效率。正确使用这些工具可显著提升程序性能,但也需注意任务取消和异常处理等常见问题。
276 1
下一篇
开通oss服务