999在线视频精品免费播放观看-国产在线观看无码免费视频-漂亮人妻被中出中文字幕-国产精品妇女一二三区

C#泛型編程已經(jīng)深入人心了。為什么又提出C#模板編程呢?因?yàn)镃#泛型存在一些局限性,突破這些局限性,需要使用C#方式的模板編程。由于C#語(yǔ)法、編譯器、IDE限制,C#模板編程沒(méi)有C++模板編程使用方便,但是,仍然可以解決一些問(wèn)題。

 

下面先看C#泛型編程的兩個(gè)限制:

(1)類型約束問(wèn)題。

C#泛型的類型約束是個(gè)很嚴(yán)重的問(wèn)題。

假設(shè)需要寫(xiě)一個(gè)泛型方法,這個(gè)方法有2個(gè)參數(shù),然后方法返回結(jié)果是這兩個(gè)參數(shù)的和。

這樣的泛型方法無(wú)法直接實(shí)現(xiàn)。因?yàn)锽yte,Int32等等并沒(méi)有公共接口。

沒(méi)有公共接口,但又想借助泛型來(lái)節(jié)省代碼,減少維護(hù)量。怎么辦呢?

我之前寫(xiě)過(guò)2篇博客《實(shí)現(xiàn).net下的動(dòng)態(tài)代理》、《實(shí)現(xiàn).net下的動(dòng)態(tài)代理(續(xù))-多對(duì)象Mixin》,通過(guò)Ducking Typing來(lái)實(shí)現(xiàn),但這種實(shí)現(xiàn)方式不自然,且性能低下,只適合對(duì)性能不敏感的場(chǎng)景。

(2)泛型指針問(wèn)題。

泛型程序中無(wú)法使用泛型指針,因?yàn)榫幾g器編譯時(shí)無(wú)法知道具體類型的Size,這對(duì)寫(xiě)unsafe代碼是很大的限制。

 

因此,我們需要C#模板編程。C#模板編程說(shuō)起來(lái)很簡(jiǎn)單,它借助的是C#的一個(gè)語(yǔ)法——Using T0=T1。它沒(méi)有C++那么自然,因?yàn)樗狈/C++源文件的Include機(jī)制。你可以將整塊的文件在不同的類之間進(jìn)行復(fù)制和粘帖。雖然復(fù)制和粘帖是一大邪惡,但總比復(fù)制/粘帖/替換要好很多。

下面是C#模板編程的一個(gè)重要應(yīng)用——圖像處理的空間線性濾波。關(guān)于空間線性濾波可參見(jiàn)各種圖像處理的書(shū),這里不做介紹。

我們假定圖像是一個(gè)泛型類Image<T0>,這里T代表每一個(gè)像素的存儲(chǔ)類型。可以是Byte,Short,Int32,Int64,Single,Double等。然后,核是一個(gè)泛型類,Kernel<T1>,這里還有第三個(gè)泛型類,就是用于存放中間數(shù)據(jù)的Image<T2>。為什么需要T2呢?假如T0是Byte,T1是帶有Scale的Int32(如,Scale=9,每個(gè)元素值=1的3*3矩陣),計(jì)算的中間結(jié)果會(huì)超出Byte的最大值,需要一個(gè)不同類型緩存來(lái)存儲(chǔ)這個(gè)中間數(shù)據(jù)。

只用泛型的話,解決不了這個(gè)問(wèn)題。第一點(diǎn),Byte,Short,Int32,Int64,Single,Double之間未實(shí)現(xiàn)共同接口;第二點(diǎn),為提升性能,Image<T>采用非托管內(nèi)存實(shí)現(xiàn),使用指針進(jìn)行操作,而泛型中無(wú)法使用泛型指針。

使用C#模板可以解決這個(gè)問(wèn)題——代碼照舊,只是在頭部寫(xiě)下:Using T0=XXX;Using T1=XXX;Using T2=XXX;即可。

由于欠缺源代碼的Include機(jī)制,當(dāng)要編寫(xiě)新的濾波器時(shí),需要把相同的代碼復(fù)制過(guò)去,然后更改頭部的Using ……。但無(wú)論如何,這樣使用,還是比在代碼中直接寫(xiě)明類型,然后復(fù)制、粘帖、替換新類型的可讀性以及可維護(hù)性要好。

如果.Net允許源代碼的Include,C#的模板編程將變得更為流暢(比起C++還是欠缺很多)。不知道等后續(xù).Net版本開(kāi)放編譯服務(wù)之后,會(huì)不會(huì)有更優(yōu)雅的寫(xiě)法。

下面是我隨便寫(xiě)下的一段對(duì)圖像進(jìn)行空間線性濾波的代碼(不要看具體算法,具體算法是極端錯(cuò)誤的,且不完整的,只用看看編碼風(fēng)格就行了,寫(xiě)這段代碼只為驗(yàn)證這種編程模式的優(yōu)點(diǎn)和缺點(diǎn)):

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;
        }
    }
}

 

是不是很像模板編程呢?